0% found this document useful (0 votes)
44 views

Compiler

Peephole optimization is a type of code optimization that operates on a small set of instructions known as the peephole or window. It works by replacing part of the code with shorter and faster code that produces the same output. The peephole is machine-dependent.

Uploaded by

Atik Pal
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
44 views

Compiler

Peephole optimization is a type of code optimization that operates on a small set of instructions known as the peephole or window. It works by replacing part of the code with shorter and faster code that produces the same output. The peephole is machine-dependent.

Uploaded by

Atik Pal
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 5

1. What is Peephole Optimization?

Peephole optimization is a type of code Optimization performed on a small part of the code. It is


performed on a very small set of instructions in a segment of code.

The small set of instructions or small part of code on which peephole optimization is performed is
known as peephole or window.

It basically works on the theory of replacement in which a part of code is replaced by shorter and faster
code without a change in output. The peephole is machine-dependent optimization. 

2.a. What do you mean by Synthesized and Inherited Attribute?


Synthesized attribute is an attribute whose parse tree node value is determined by the attribute value at
child nodes. To illustrate, assume the following production S → ABC if S is taking values from its child
nodes (A, B, C), then it is said to be a synthesized attribute, as the values of ABC are synthesized to S.

On other hand an attribute is said to be Inherited attribute if its parse tree node value is determined by
the attribute value at parent and/or sibling nodes. In case of S → ABC if A can get values from S, B and C.
B can take values from S, A, and C. Likewise, C can take values from S, A, and B then S is said to be
Inherited Attribute.

2.b. What is an annotated parse tree?


AN ANNOTATED PARSE TREE. is a parse tree showing the values of the attributes at each node. The
process of computing the attribute values at the nodes is called annotating or decorating the parse tree.

2.c. What do you mean by terminal table and literal table?


Terminal table is a permanent database that has entry for each terminal symbol such as arithmetic
operators, keywords, punctuations, and characters.

In computer science, and specifically in compiler and assembler design, a literal pool is a lookup


table used to hold literals during assembly and execution. The literal table contains the literal name,
operand value and length.

3.a. What are the main contributions of syntax directed translation in the
compiler?
The syntax-directed translation scheme is beneficial because it allows the compiler designer to define
the generation of intermediate code directly in terms of the syntactic structure of the source language.
It is division into two subsets known as synthesized and inherited attributes of grammar.
4. What is Type Checking?
Type checking is the process of verifying and enforcing constraints of types in values. A compiler must
check that the source program should follow the syntactic and semantic conventions of the source
language and it should also check the type rules of the language. It allows the programmer to limit what
types may be used in certain circumstances and assigns types to values. The type-checker determines
whether these values are used appropriately or not.

It checks the type of objects and reports a type error in the case of a violation, and incorrect types are
corrected. Whatever the compiler we use, while it is compiling the program, it has to follow the type
rules of the language. Every language has its own set of type rules for the language. We know that the
information about data types is maintained and computed by the compiler.
5.a. What is Augmented Grammar?
An augmented grammar is any grammar whose productions are augmented with conditions expressed
using features. Features may be associated with any nonterminal symbol in a derivation. A feature
associated with a nonterminal symbol is shown following that nonterminal separated from it by a "."

OR

In compiler design, an augmented grammar refers to a modified version of a context-free grammar


(CFG) that includes additional elements to facilitate the parsing process. The augmented grammar is
typically used in conjunction with parsing algorithms such as LR (left-to-right, rightmost derivation) or
LALR (look-ahead LR) parsers.

The augmented grammar introduces a new start symbol and a new production rule. The new start
symbol represents the entire program or input to be parsed, and the new production rule defines the
relationship between the start symbol and the original start symbol of the grammar.

5.b. What do you mean by LR(0) items?


In compiler design, LR(0) items are used in bottom-up parsing algorithms, such as LR(0) parsing, to
represent the states and transitions of a parser's state machine. An LR(0) item consists of a production
rule from the grammar and a marker that represents the current position within that rule.

7.i. Loop Optimization:


Loop optimization is a crucial aspect of compiler optimization techniques that focuses on improving the
efficiency and performance of loops in code. Since loops often consume a significant portion of
execution time in programs, optimizing them can have a substantial impact on overall program speed.

The goal of loop optimization is to transform the loop code to reduce unnecessary computations,
minimize memory access, exploit parallelism, and enhance cache utilization. By making the loop more
efficient, loop optimization aims to decrease the number of instructions executed, reduce memory
accesses, and improve the utilization of hardware resources.

7.ii Dependency Graph


A dependency graph, also known as a data dependency graph or a control-flow graph, is a graphical
representation of the dependencies between instructions or data in a program. It is commonly used in
compiler design and optimization to analyze and optimize code.

In a dependency graph, nodes represent individual instructions or operations, and edges represent
dependencies between them. The dependencies can be classified into two main types:
a. Data Dependency: Data dependencies represent the flow of data between instructions. They
indicate that the output of one instruction is dependent on the input or result of another
instruction. Data dependencies can be further categorized into three types:

Read-after-Write (RAW) dependency: A node reads data that was written by a previous node.

Write-after-Read (WAR) dependency: A node writes data that will be subsequently read by a
later node.

Write-after-Write (WAW) dependency: Two nodes write to the same location, and the order of
writes affects the final value.

b. Control Dependency: Control dependencies represent the flow of control within a program.
They indicate the ordering and conditions for executing instructions. Control dependencies are
typically represented by conditional branches, loops, and jumps.

7.iii L-Attributed Graph:


L-Attributed definition refers to a set of constraints imposed on the attributes of a context-free grammar
(CFG). These constraints specify the order in which attributes of grammar symbols (terminals and non-
terminals) can be evaluated during a syntax-directed translation or semantic analysis process.

In an L-Attributed definition, the evaluation of attributes follows a top-down, left-to-right (hence the "L"
in L-Attributed) traversal of the parse tree or the input. It means that the attributes of a grammar
symbol can depend only on the attributes of its immediate left siblings and its own inherited attributes
(attributes passed from its parent).

The L-Attributed definition typically satisfies the following properties:

No Cycles: There should be no cyclic dependencies among attributes. In other words, the dependencies
among attributes should form a directed acyclic graph (DAG). This ensures that attribute evaluation can
proceed without encountering circular dependencies.

Locality: The attributes of a grammar symbol can be computed using only information available at or
above that symbol's position in the parse tree. The attributes should not depend on information from
distant siblings or descendants in the tree.

Synthesized and Inherited Attributes: The attributes can be classified into two types: synthesized
attributes and inherited attributes. Synthesized attributes are computed from the attributes of child
nodes, while inherited attributes are passed from parent nodes to child nodes. In an L-Attributed
definition, synthesized attributes are typically computed before inherited attributes.

7.iv. LEX and YACC:


LEX and YACC are widely used tools in compiler construction for generating lexical analyzers (scanners)
and parsers, respectively. They are often used together to build the front-end of a compiler or an
interpreter for programming languages.
a. LEX (or Flex): LEX is a lexical analyzer generator. It takes a set of regular expressions and
corresponding action rules as input and generates a lexical analyzer in C or C++ code. The
generated scanner reads input characters from a source file or input stream, matches them
against the regular expressions, and performs the specified actions when a match is found. LEX
greatly simplifies the task of tokenizing input into meaningful tokens, which are then passed to
the parser for further processing.
b. YACC (or Bison): YACC is a parser generator that generates LALR(1) (Look-Ahead LR with one
symbol of lookahead) parsers. It takes a set of grammar rules with associated actions and
generates a parser in C or C++ code. YACC uses a formal context-free grammar specification to
define the syntax of a programming language or other input language. The generated parser
reads tokens from the lexical analyzer (scanner) and matches them against the grammar rules to
construct a parse tree or perform other specified actions. YACC provides powerful capabilities
for handling operator precedence, associativity, and grammar ambiguity.

Together, LEX and YACC (or Flex and Bison, their modern counterparts) provide a powerful toolset for
building the front-end of a compiler. LEX handles the tokenization phase by generating efficient lexical
analyzers, while YACC handles the parsing phase by generating parsers based on context-free grammars.
By using these tools, developers can focus on defining the language syntax and semantics rather than
implementing the low-level details of tokenizing and parsing.

7.v. Input Buffering:


Input buffering, in the context of compiler design, refers to the process of reading input characters or
tokens from the source program and buffering them in memory before passing them to the lexical
analyzer (also known as the scanner).

Input buffering is an important step in the lexical analysis phase, which is the initial stage of the
compiler. The purpose of input buffering is to reduce the overhead of reading characters or tokens one
at a time from the source program, which can be time-consuming and inefficient. Instead, input
buffering allows the lexical analyzer to retrieve a block or a batch of characters or tokens from memory,
improving the overall efficiency of the scanning process.

The buffering mechanism typically involves a buffer or a queue that temporarily stores the input
characters or tokens read from the source program. The size of the buffer can vary depending on the
specific implementation or requirements of the compiler.

You might also like