Compiler Design 1-1
Compiler Design 1-1
Irfan Rasool
What is a Compiler?
A compiler is a specialized software that converts code written in a high-level programming
language (such as C, C++, Java) into machine code (binary or assembly language), which
can be directly executed by a computer's processor.
The process of compiling ensures that human-readable instructions (source code) are
translated into the low-level instructions that the machine can understand and execute.
For example:
● One-Time Translation: A compiler typically translates the entire program in one go,
unlike an interpreter that processes code line by line during runtime.
● Generates Executable: Once the code is compiled, it produces an executable file that
can be run independently of the source code and the compiler.
● Error Checking: During the compilation process, the compiler checks the source code
for syntactic and semantic errors before generating the executable. These errors must
be fixed by the programmer before the program can run successfully.
Where We Use Compilers
● Parsers for HTML in web browser
● Interpreters for javascript/flash
● Machine code generation for high level languages
● Software testing
● Program optimization
● Malicious code detection
● Design of new computer architectures
○ Compiler-in-the-loop hardware development
● Hardware synthesis: VHDL to RTL translation
● Compiled simulation
○ Used to simulate designs written in VHDL
○ No interpretation of design, hence faster
Why Do We Need Compilers?
Compilers are essential for several reasons:
● type checking, static analysis, dependence analysis and loop parallelization, cache
analysis, etc.
Functions:
Example:
● Input: int a = 5;
● Output: INT_KEYWORD IDENTIFIER ASSIGNMENT_OPERATOR CONSTANT SEMICOLON
Syntax Analysis (Parsing)
Converts token stream into a parse tree or abstract syntax tree (AST).
Functions:
Parsing Techniques:
Functions:
Example:
Forms of IR:
Goals:
Optimization Techniques:
● Constant folding.
● Dead code elimination.
● Loop unrolling.
Code Generation
Translates optimized intermediate code into machine code or assembly.
Challenges:
● Register allocation.
● Instruction selection for the target architecture.
Example:
The code is then assembled into a final executable binary file, ready to run on the target
machine.
Error Handling
Types of Errors:
● Panic-mode recovery.
● Phrase-level recovery.
Compiler vs. Interpreter
● Compiler:
○ Translates the entire program at once.
○ Produces an independent executable.
○ Faster execution after compilation but slower to compile.
● Interpreter:
○ Translates and executes code line-by-line.
○ Does not produce an independent executable.
○ Slower execution time but faster to start running.
● Compilers generate machine code, whereas interpreters interpret
intermediate code
● Interpreters are easier to write and can provide better error
messages (symbol table is still available)
● Interpreters are at least 5 times slower than machine code
generated by compilers
● Interpreters also require much more memory than machine code
generated by compilers
● While both compilers and interpreters translate high-level code
into machine-understandable instructions, they differ in how they
do this.
Types of Compilers
There are various types of compilers depending on the target language, source language, or
the system they are designed for:
● Single-pass Compilers: These compilers go through the source code once and produce
machine code. They are typically fast but less powerful.
● Multi-pass Compilers: These compilers go through the source code multiple times (in
different passes), performing deeper analysis and optimizations.
● Cross Compilers: Compilers that generate machine code for a different architecture
than the one the compiler is running on.
● Just-in-Time (JIT) Compilers: A combination of an interpreter and compiler. JIT
compiles code during runtime for faster execution (used in environments like Java and
.NET).
Applications of Compilers
1. Translation of High-Level Languages to Machine Code
Example Applications:
● Java Native Interface (JNI): Java programs can call native C or C++ code for tasks
requiring high performance, like hardware interfacing or system-level operations.
● .NET Framework: The Common Language Runtime (CLR) in .NET compiles code from
various languages (C#, VB.NET, F#) into a common intermediate language (CIL),
enabling them to work seamlessly together.
Applications of Compilers
4. Enabling Just-in-Time (JIT) Compilation
Just-in-Time (JIT) compilers are used in managed runtime environments like the Java Virtual Machine (JVM)
and .NET's Common Language Runtime (CLR). JIT compilation involves compiling code during runtime rather
than before execution, offering several advantages:
● Performance Optimization at Runtime: JIT compilers can make optimizations based on the program’s
execution environment, such as CPU architecture, memory availability, and typical data patterns.
● Adaptive Execution: The compiler can optimize code paths that are frequently used while keeping
rarely used code in a less optimized state. This is particularly effective in dynamic languages like
JavaScript or Java.
JIT compilers are heavily used in environments that require a balance between flexibility and performance,
such as:
● Static Analysis Tools: Many compilers can perform static code analysis during the
compilation process. This helps in detecting:
○ Syntax errors.
○ Type mismatches.
○ Potentially dangerous code patterns (such as buffer overflows or memory leaks).
● Integrated Debugging: Compilers generate debugging information that allows tools like
gdb or Visual Studio Debugger to step through source code, monitor variables, and set
breakpoints.
○ These features enhance developer productivity and help ensure that software is both correct
and efficient.
Applications of Compilers
7. Supporting Parallel and Distributed Computing
Compilers for parallel computing and distributed systems translate code into machine
instructions that can execute efficiently on multiple processors or distributed systems. They
play a key role in:
● Scientific computing, simulations, and machine learning benefit from compilers that
generate parallel code to exploit supercomputing resources.
Applications of Compilers
8. Dynamic Language Compilation
In languages like Python, JavaScript, and Ruby, compilers play a key role in improving
execution efficiency through techniques like Just-in-Time (JIT) compilation and
ahead-of-time (AOT) compilation.