Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
3 views23 pages

Principles of Programming Lànguage

The document discusses the importance of studying programming languages, highlighting benefits such as improved expression of ideas, better language selection, and enhanced learning of new languages. It categorizes programming languages by their domains and paradigms, and outlines evaluation criteria for assessing their suitability. Additionally, it covers language design trade-offs, implementation methods, and the compilation process, emphasizing the complexities involved in programming language development.

Uploaded by

kodumurisusena
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)
3 views23 pages

Principles of Programming Lànguage

The document discusses the importance of studying programming languages, highlighting benefits such as improved expression of ideas, better language selection, and enhanced learning of new languages. It categorizes programming languages by their domains and paradigms, and outlines evaluation criteria for assessing their suitability. Additionally, it covers language design trade-offs, implementation methods, and the compilation process, emphasizing the complexities involved in programming language development.

Uploaded by

kodumurisusena
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/ 23

UNIT I

Studying the concepts of programming languages, often


within a "Principles of Programming Languages" (PPL)
course, offers several significant benefits (or) Reasons
for Studying Principles of Programming Languages

Increased Capacity to Express Ideas:


Understanding diverse language constructs and paradigms expands a programmer's
ability to articulate and implement solutions more effectively, even when using a
familiar language. Awareness of features found in other languages can inform creative
solutions in the language being used.

Improved Background for Choosing Appropriate Languages:


Knowledge of various language types and their strengths and weaknesses enables
informed decisions when selecting the most suitable language for a specific project,
rather than defaulting to a familiar but potentially suboptimal choice.

Increased Ability to Learn New Languages:


Familiarity with fundamental concepts like data types, control structures, and
abstraction mechanisms, which are common across many languages, significantly
accelerates the process of learning new programming languages.

Better Understanding of the Significance of Implementation:

Studying how language constructs are implemented provides insights into their design
choices and performance implications, leading to more efficient coding and effective
debugging.

Better Use of Languages Already Known:


Deeper understanding of the underlying principles and features of familiar languages,
even those not frequently used, can lead to more effective and idiomatic use of those
languages.

Overall Advancement of Computing:


A comprehensive understanding of programming language concepts contributes to
the broader field of computer science by fostering innovation in language design
and promoting more robust and efficient software development practices.
PROGRAMMING DOMAINS :
Programming languages are applied across various domains, including
scientific computing, business applications, artificial intelligence, systems
programming, and web development. These domains utilize different
languages and programming paradigms to address specific needs and
challenges.

Here’s a breakdown of some key programming domains and the languages


commonly associated with them:
1.Scientific Applications:
Focus: High-performance computing, numerical analysis, simulations, and
research involving complex calculations with floating-point numbers.
Languages: FORTRAN, MATLAB, R, Python (with libraries like NumPy and
SciPy).
Example: Simulating weather patterns, analyzing scientific data, or modeling
physical phenomena.

2.Business Applications:
Focus: Data processing, financial transactions, reporting, and management
information systems.
Languages: COBOL, Java, C#, Python.
Example: Banking systems, inventory management, and accounting software.

3.Artificial Intelligence (AI):


Focus: Machine learning, natural language processing, knowledge
representation, and expert systems.
Languages: LISP, Prolog, Python (with libraries like TensorFlow and PyTorch), R.
Example: Building chatbots, developing image recognition algorithms, and
creating recommendation systems.

4.Systems Programming:
Focus: Operating systems, device drivers, embedded systems, and low-level
system software.
Languages: C, C++, Assembly language.
Example: Developing the core components of an operating system like
Windows or Linux, or creating firmware for microcontrollers.

5.Web Development:
Focus: Creating and maintaining websites and web applications.
Languages: HTML, CSS, JavaScript, PHP, Python (with frameworks like Django
and Flask), Java (with frameworks like Spring), Ruby on Rails.
Example: Building e-commerce websites, social media platforms, and online
portals.

6.Scripting Languages:
Focus: Automating tasks, system administration, and rapid prototyping.
Languages: JavaScript, Python, Perl, Bash.
Example: Writing scripts to automate file backups, process data, or configure
network settings.

7.Special Purpose Languages:


Focus: Languages designed for specific applications like database query
languages (SQL), graphical programming languages (e.g., for CAD/CAM), or
domain-specific languages for areas like finance or scientific modeling.
Languages: SQL, MATLAB, VHDL.
Example: Developing a database query to retrieve specific information,
creating a 3D model of a product, or modeling a circuit design.

8.Functional Programming:
Focus: Emphasizing the evaluation of functions and avoiding changing state or
mutable data.
Languages: Haskell, Lisp, Scala, Erlang.
Example: Developing concurrent systems, data processing pipelines, and
complex algorithms where immutability is crucial.
Understanding these different programming domains and the languages used
within them is crucial for choosing the right tools for a particular project and
for developing effective and efficient software solutions.
LANGUAGE EVALUATION CRITERIA:
In the context of Principles of Programming Languages (PPL), the
evaluation criteria for programming languages are used to assess their
suitability for various applications and their overall quality. The primary
criteria include:
Readability:
This refers to the ease with which programs written in the language can
be read and understood by humans. Factors contributing to readability
include:
Simplicity: A manageable set of features and constructs, minimal feature
multiplicity (multiple ways to achieve the same operation), and limited
operator overloading.
Orthogonality: A relatively small set of primitive constructs that can be
combined in a small number of ways, with every combination being legal.
Control Statements: The presence of well-known and structured control
flow mechanisms (e.g., while, for, if-else).
Data Types and Structures: Adequate facilities for defining and using data
types and structures.
Syntax Considerations: Clear and self-descriptive syntax, meaningful
keywords, and flexible identifier forms.
Writability:
This measures how easily a language can be used to create programs for
a chosen problem domain. It is closely related to readability and often
influenced by:
Simplicity and Orthogonality: As described above, these also
contribute to ease of writing.
Support for Abstraction: The ability to define and use complex
structures or operations without needing to know their internal details.
Reliability:
This indicates the extent to which a program written in the language
performs to its specifications under all conditions. Key aspects include:
Type Checking: The language's ability to detect type errors, either at
compile time or runtime.
Exception Handling: Mechanisms for gracefully handling runtime errors
and exceptional conditions.
Aliasing: The potential for multiple names to refer to the same memory
location, which can impact program behavior.
Cost:
This encompasses the ultimate total cost associated with using a
programming language throughout its lifecycle. This includes:
Cost of training programmers.
Cost of writing programs.
Cost of compiling and executing programs.
Cost of the language implementation system.
Cost of poor reliability.
Cost of maintaining programs.
Other important, though sometimes secondary, criteria can include:
Generality: The range of applications for which the language is suitable.
Extensibility: The ability to extend the language with new features or
constructs.
Standardability: The existence and adherence to industry standards.
Support for Internationalization: The ease with which programs can be
adapted for different languages and cultures.
The design of programming languages is
influenced by several factors, including:

Computer Architecture:

The prevalent computer architecture, particularly the von Neumann


architecture, has significantly shaped language design. This architecture,
with its stored programs and data in a single memory and a separate
CPU, led to the development of imperative languages that emphasize
variables, assignment statements, and iterative control structures to
manipulate memory locations.
Programming Design Methodologies:

The evolution of software development methodologies has driven


changes in language design.

Structured programming: This movement emphasized control flow


structures and modularity, leading to features like procedures and
functions.

Data-oriented programming: Increased focus on data organization and


abstraction led to features supporting abstract data types and data
hiding.

Object-oriented programming (OOP): The rise of OOP paradigms,


emphasizing encapsulation, inheritance, and polymorphism, influenced
the design of languages like Smalltalk, C++, and Java, which incorporate
classes and objects as fundamental constructs.

PROGRAMMING LANGUAGES CATAGORIES

In the context of Principles of Programming Languages (PPL), programming languages are


categorized in several ways, primarily based on their level of abstraction and their
underlying programming paradigms.

1. Classification by Level of Abstraction:

Machine Language:
This is the lowest-level language, directly understood by the computer’s hardware,
consisting of binary code (0s and 1s).
Assembly Language:
A low-level language that uses mnemonics to represent machine instructions, offering a
slightly more human-readable form than machine language. It still requires an assembler to
translate it into machine code.
High-Level Languages:
These languages are designed to be more human-readable and abstract, using syntax closer
to natural language. They require a compiler or interpreter to translate them into machine
code or an intermediate form. Examples include C++, Python, and Java.
2. Classification by Programming Paradigm:

Imperative Languages:
Focus on describing how a program should achieve a result through a sequence of
instructions that modify program state. Examples: C, Pascal.
Functional Languages:
Emphasize computation as the evaluation of mathematical functions, avoiding mutable state
and side effects. Examples: LISP, Scheme.
Object-Oriented Languages (OOP):
Organize programs around “objects” that combine data (attributes) and behavior (methods),
supporting concepts like encapsulation, inheritance, and polymorphism. Examples: Java, C+
+.
Logic Languages:
Based on formal logic, where programs express facts and rules, and the system attempts to
find solutions by logical deduction. Example: Prolog.
Scripting Languages:
Often used for automating tasks, web development, and system administration, known for
their ease of use and often interpreted execution. Examples: Python, JavaScript, Ruby.
Markup Languages:
Not programming languages in the traditional sense, but used to structure and present
information, particularly for web documents. Examples: HTML, XML.

PROGRAMMING LANGUAGE DESIGN TRADE-OFF

In Principles of Programming Languages (PPL), language design involves various trade-offs,


as optimizing one aspect often comes at the expense of another. Key trade-offs include:

Reliability vs. Cost of Execution:

Reliability: Languages that prioritize reliability often include features like strict type
checking, bounds checking for arrays, and robust error handling mechanisms. These features
help prevent common programming errors and ensure predictable program behavior.

Cost of Execution: The overhead introduced by these reliability features can lead to slower
execution speeds. For example, Java’s array bounds checking enhances reliability but incurs
a performance cost compared to languages like C, which typically omit such checks.

Readability vs. Writability (Expressiveness):

Readability: A language is considered readable if its syntax and structure are easy to
understand and follow, making code maintenance and collaboration simpler. Features like
clear control structures, meaningful keywords, and consistent syntax contribute to
readability.
Writability/Expressiveness: A language is writable or expressive if it allows programmers
to write complex operations concisely and efficiently. This can sometimes involve using
powerful operators or highly compact syntax, which may reduce readability for those
unfamiliar with the conventions. APL, with its extensive set of symbols and operators,
exemplifies a language prioritizing expressiveness, potentially at the cost of immediate
readability.
Writability (Flexibility) vs. Reliability:

Writability/Flexibility: Some language features offer great flexibility in how programmers


can manipulate data and memory, enabling powerful and optimized solutions. C++ pointers
are a prime example, providing direct memory access and manipulation capabilities.

Reliability: This flexibility can also introduce opportunities for errors, such as memory leaks
or invalid memory access, which can compromise program reliability. Languages that
prioritize reliability may restrict such flexible but potentially unsafe features.

Simplicity vs. Power/Generality:


Simplicity: Simpler languages with fewer constructs are generally easier to learn and use,
reducing the cognitive load on programmers.

Power/Generality: More powerful or general-purpose languages often include a wider range


of features and constructs to handle diverse programming tasks, which can increase
complexity.
These trade-offs are fundamental considerations during language design, as the optimal
balance depends on the primary methods for implementing programming languages are
compilation, interpretation, and hybrid approaches. Compilation translates the entire
program into machine code before execution, while interpretation executes the program line
by line. Hybrid systems combine compilation and interpretation. intended application
domain and the priorities of the language creators.

What goes inside the compilation process?

A compiler converts a C program into an executable. There are four phases for a C program
to become an executable:

>Pre-processing

>Compilation

>Assembly

>Linking

1.Pre-processing

This is the first phase through which source code is passed. This phase includes: Removal
of Comments
Expansion of Macros

Expansion of the included files.

Conditional compilation

2.Compilation
In programming, compilation is the process of translating source code (written in a human-
readable programming language) into machine code (a language that a computer can directly
execute). This transformation is performed by a compiler, a specialized software tool.

3.Assembling

In computer programming, “assembling” refers to the process of translating assembly


language code into machine code that a computer can understand and execute. This
translation is performed by a program called an assembler. Essentially, the assembler takes
human-readable assembly language instructions and converts them into a format the
computer’s processor can directly process.

4.Linking

This is the final phase in which all the linking of function calls with their definitions is done.
Linker knows where all these functions are implemented. Linker does some extra work also:
it adds some extra code to our program which is required when the program starts and ends.
For example, there is a code that is required for setting up the environment like passing
command line arguments. This task can be easily verified by using size filename.o and size
filename. Through these commands, we know how the output file increases from an object
file to an executable file. This is because of the extra code that Linker adds to our program.

Linking can be of two types:

Static Linking: All the code is copied to the single file and then executable file is created.

Dynamic Linking: Only the names of the shared libraries is added to the code and then it is
referred during the execution.

IMPLEMENTATION METHODS

The primary methods for implementing programming languages


are compilation, interpretation, and hybrid approaches. Compilation
translates the entire program into machine code before execution, while
interpretation executes the program line by line. Hybrid systems combine
compilation and interpretation.
1. Compilation:
A compiler translates the entire source code into machine code (or an
intermediate representation) before execution.
The compiled code can then be executed directly by the computer, often
resulting in faster execution times.
Examples of languages using this approach include C, C++, and Ada.
Phases in Compiler:

1. Lexical Analysis
Lexical analysis is the first phase of a compiler, responsible for
converting the raw source code into a sequence of tokens. A
token is the smallest unit of meaningful data in a programming
language. Lexical analysis involves scanning the source code,
recognizing patterns, and categorizing groups of characters into
distinct tokens.

The lexical analyzer scans the source code character by


character, grouping these characters into meaningful units
(tokens) based on the language’s syntax rules. These tokens can
represent keywords, identifiers, constants, operators, or
punctuation marks. By converting the source code into tokens,
lexical analysis simplifies the process of understanding and
processing the code in later stages of compilation.

Example: int x = 10;

The lexical analyzer would break this line into the following
tokens:

Int - Keyword token (data type)


X - Identifier token (variable name)
= - Operator token (assignment operator)
10 - Numeric literal token (integer value)
; - Punctuation token (semicolon, used to terminate
statements)

Each of these tokens is then passed on to the next phase of the


compiler for further processing, such as syntax analysis.

2. Syntax Analysis
Syntax analysis, also known as parsing, is the second phase of a
compiler where the structure of the source code is checked. This
phase ensures that the code follows the correct grammatical
rules of the programming language.

The role of syntax analysis is to verify that the sequence of


tokens produced by the lexical analyzer is arranged in a valid way
according to the language’s syntax. It checks whether the code
adheres to the language’s rules, such as correct use of operators,
keywords, and parentheses. If the source code is not structured
correctly, the syntax analyzer will generate errors.
To represent the structure of the source code, syntax analysis
uses parse trees or syntax trees.

Parse Tree: A parse tree is a tree-like structure that represents


the syntactic structure of the source code. It shows how the
tokens relate to each other according to the grammar rules. Each
branch in the tree represents a production rule of the language,
and the leaves represent the tokens.
Syntax Tree: A syntax tree is a more abstract version of the parse
tree. It represents the hierarchical structure of the source code
but with less detail, focusing on the essential syntactic structure.
It helps in understanding how different parts of the code relate
to each other.

3.Semantic Analysis
Semantic analysis is the phase of the compiler that ensures the
source code makes sense logically. It goes beyond the syntax of
the code and checks whether the program has any semantic
errors, such as type mismatches or undeclared variables.

Semantic analysis checks the meaning of the program by


validating that the operations performed in the code are logically
correct. This phase ensures that the source code follows the
rules of the programming language in terms of its logic and data
usage.

Some key checks performed during semantic analysis include:


Type Checking: The compiler ensures that operations are
performed on compatible data types. For example, trying to add
a string and an integer would be flagged as an error because
they are incompatible types.
Variable Declaration: It checks whether variables are declared
before they are used. For example, using a variable that has not
been defined earlier in the code would result in a semantic error.
Example:

Int a = 5;
Float b = 3.5;
a = a + b;

Type Checking:

a is int and b is float. Adding them (a + b) results in float, which


cannot be assigned to int a.
Error: Type mismatch: cannot assign float to int.

4.Intermediate Code Generation


Intermediate code is a form of code that lies between the high-
level source code and the final machine code. It is not specific to
any particular machine, making it portable and easier to
optimize. Intermediate code acts as a bridge, simplifying the
process of converting source code into executable code.

The use of intermediate code plays a crucial role in optimizing


the program before it is turned into machine code.

Platform Independence: Since the intermediate code is not tied


to any specific hardware, it can be easily optimized for different
platforms without needing to recompile the entire source code.
This makes the process more efficient for cross-platform
development.
Simplifying Optimization: Intermediate code simplifies the
optimization process by providing a clearer, more structured view
of the program. This makes it easier to apply optimization
techniques such as:
Dead Code Elimination: Removing parts of the code that don’t
affect the program’s output.
Loop Optimization: Improving loops to make them run faster or
consume less memory.
Common Subexpression Elimination: Reusing previously
calculated values to avoid redundant calculations.
Easier Translation: Intermediate code is often closer to machine
code, but not specific to any one machine, making it easier to
convert into the target machine code. This step is typically
handled in the back end of the compiler, allowing for smoother
and more efficient code generation.
Example: a = b + c * d;

T1 = c * d
T2 = b + t1
A = t2

5.Code Optimization
Code Optimization is the process of improving the intermediate
or target code to make the program run faster, use less memory,
or be more efficient, without altering its functionality. It involves
techniques like removing unnecessary computations, reducing
redundancy, and reorganizing code to achieve better
performance. Optimization is classified broadly into two types:

Machine-Independent
Machine-Dependent
Common Techniques:

Constant Folding: Precomputing constant expressions.


Dead Code Elimination: Removing unreachable or unused code.
Loop Optimization: Improving loop performance through
invariant code motion or unrolling.
Strength Reduction: Replacing expensive operations with simpler
ones.

Example:

Code Before Optimization:


For ( int j = 0 ; j < n ; j ++)
{
X=y+z;
A[j] = 6 x j;
}

Code After Optimization:


X=y+z;
For ( int j = 0 ; j < n ; j ++)
{
A[j] = 6 x j;
}

6.Code Generation
Code Generation is the final phase of a compiler, where the
intermediate representation of the source program (e.g., three-
address code or abstract syntax tree) is translated into machine
code or assembly code. This machine code is specific to the
target platform and can be executed directly by the hardware.
The code generated by the compiler is an object code of some
lower-level programming language, for example, assembly
language. The source code written in a higher-level language is
transformed into a lower-level language that results in a lower-
level object code, which should have the following minimum
properties:

It should carry the exact meaning of the source code.


It should be efficient in terms of CPU usage and memory
management.

Example:
Three Address
Code Assembly Code

LOAD R1, c ; Load the value of 'c' into


register R1
LOAD R2, d ; Load the value of 'd' into
register R2
MUL R1, R2 ; R1 = c * d, store result in R1
LOAD R3, b ; Load the value of 'b' into
register R3
ADD R3, R1 ; R3 = b + (c * d), store result
t1 = c * d in R3
t2 = b + t1 STORE a, R3 ; Store the final result in
a = t2 variable 'a'

Symbol Table: – It is a data structure being used and


maintained by the compiler, consisting of all the identifier’s
names along with their types. It helps the compiler to function
smoothly by finding the identifiers quickly.

Error Handling in Phases of Compiler:


Error Handling refers to the mechanism in each phase of the
compiler to detect, report and recover from errors without
terminating the entire compilation process.
Lexical Analysis: Detects errors in the character stream and
ensures valid token formation.
Example: Identifies illegal characters or invalid tokens (e.g., @var
as an identifier).
Syntax Analysis: Checks for structural or grammatical errors
based on the language’s grammar.
Example: Detects missing semicolons or unmatched parentheses.
Semantic Analysis: Verifies the meaning of the code and ensures
it follows language semantics.
Example: Reports undeclared variables or type mismatches (e.g.,
adding a string to an integer).
Intermediate Code Generation: Ensures the correctness of
intermediate representations used in further stages.
Example: Detects invalid operations, such as dividing by zero.
Code Optimization: Ensures that the optimization process doesn’t
produce errors or alter code functionality.
Example: Identifies issues with unreachable or redundant code.
Code Generation: Handles errors in generating machine code or
allocating resources.
Example: Reports insufficient registers or invalid machine
instructions.

3. Interpretation:

Interpretation in programming refers to the direct execution of


instructions in a programming language by an interpreter, without the
need for a separate compilation step into machine code before execution.
Here's a breakdown of what that entails:
Direct Execution:
An interpreter reads and executes the source code line by line, or
instruction by instruction, at runtime. This contrasts with compiled
languages, where the entire source code is translated into a machine-
executable format (like an .exe file) before the program runs.
No Separate Compilation:
Unlike compiled languages, interpreted languages do not require a
distinct compilation phase to create an executable file. The interpreter
handles the translation and execution process dynamically as the
program runs.
Intermediate Code (Optional):
While some interpreters execute source code directly, others might first
translate the source code into an intermediate representation, such as
bytecode, which is then executed by a virtual machine or a runtime
environment. Python and Java (with its JVM) are examples of languages
that use this approach.

Flexibility and Rapid Development:


Interpretation offers advantages in terms of flexibility and rapid
development. Changes to the code can be tested immediately without
recompilation, making the development and debugging process faster.
Examples:
Popular interpreted languages include Python, JavaScript, Ruby, Perl, and
PHP. These languages are widely used in web development, scripting, and
various other applications where quick iteration and ease of use are
prioritized.

Advantages and Disadvantages of Interpreters


The advantage of the interpreter is that it is executed line by line which
helps users to find errors easily.
The disadvantage of the interpreter is that it takes more time to execute
successfully than the compiler.
Applications of Interpreters
Each operator executed in a command language is usually an invocation
of a complex routine, such as an editor or compiler so they are frequently
used to command languages and glue languages.
Virtualization is often used when the intended architecture is unavailable.
Sand-boxing
Self-modifying code can be easily implemented in an interpreted
language.
Emulator for running Computer software written for obsolete and
unavailable hardware on more modern equipment.
Some examples of programming languages that use interpreters are
Python, Ruby, Perl, PHP, and MATLAB.

3. Hybrid Implementation:
Hybrid systems combine aspects of both compilation and interpretation.
They might compile the source code into an intermediate representation,
which is then interpreted.
Just-in-time (JIT) compilation, a form of hybrid implementation, compiles
parts of the code during runtime.
This approach aims to leverage the benefits of both compilation (faster
execution) and interpretation (easier debugging).
Case study

Java:

Java, whose goal is to write once, run anywhere ,then Java interprets
to come platform-independent (i.e. portability). Thus, his
applications compile to bytecode, also called portable code or p-
code, that can be run on Java Virtual Machine, which translates to
the Java bytecode into the host machine. So bytecode is an
intermediate representation.

Summary:

You might also like