0% found this document useful (0 votes)
33 views31 pages

PYQs Unit 2 CD

The document discusses the importance of parsers in compilers, explaining the role of abstract syntax trees and context-free grammars (CFG) in parsing. It outlines different parsing techniques, including top-down (like predictive parsing) and bottom-up (like shift-reduce parsing), along with their characteristics and examples. Additionally, it covers LALR(1) parsing, detailing its features, advantages, and the process of constructing parsing tables and DFA.

Uploaded by

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

PYQs Unit 2 CD

The document discusses the importance of parsers in compilers, explaining the role of abstract syntax trees and context-free grammars (CFG) in parsing. It outlines different parsing techniques, including top-down (like predictive parsing) and bottom-up (like shift-reduce parsing), along with their characteristics and examples. Additionally, it covers LALR(1) parsing, detailing its features, advantages, and the process of constructing parsing tables and DFA.

Uploaded by

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

2021

Q.3 (a) What is the importance of a parser in Compiler? What is the role of abstract syntax trees in
parsing?

Ans-
(b) Define context free grammar and its relationship with parsing using a suitable example. When is
a grammar said to be ambiguous?
Relationship Between CFG and Parsing

• Parsing is the process of analyzing a sequence of tokens (from the lexer) to determine
if it follows the rules of the CFG.
• The parser uses the CFG to build a parse tree or abstract syntax tree.
• If a token sequence can be derived from the start symbol using the CFG, it is
syntactically valid.

Example CFG (for simple arithmetic expressions):

E → E + E
| E * E
| ( E )
| id

Here:

• E is the non-terminal (expression)


• id, +, *, (, ) are terminals

Input: id + id * id
This CFG helps the parser decide:

• Whether the expression is valid


• How to group the operators (i.e., operator precedence and associativity)

Q.4 What are the different types of Top-down parsing techniques? Bring out the distinction between
shift-reduce parsing and recursive descent parsing.

Ans-
Predictive Parsing:

Predictive Parsing is a type of top-down parsing that uses a lookahead symbol (usually one token)
to predict which production rule to apply. It does not require backtracking — meaning it makes
decisions based on a limited number of lookahead symbols without needing to try different
possibilities.

It is commonly used for LL(1) grammars, where:


• The first L means scanning the input from Left to right
• The second L means producing a Leftmost derivation
• 1 means it uses 1 lookahead token

🔄 Steps in Predictive Parsing

1. Start with the start symbol of the grammar.


2. Use a lookahead token from the input to choose a production.
3. Replace the non-terminal with the right-hand side of the selected production.
4. Repeat this until the entire input is matched.

🔧 How Predictive Parsing Works Internally

It uses:

• A parsing stack to store symbols (initially containing the start symbol).


• A lookahead pointer to the next input token.
• A predictive parsing table, also called the LL(1) parsing table.

The table guides the parser by saying:


“If the top of the stack is A and the lookahead token is a, use production A → α.”

📘 Example Grammar (LL(1) Grammar)

Let’s say we have the following grammar:

pgsql
CopyEdit
E → T E'
E' → + T E' | ε
T → id

FIRST and FOLLOW sets:

• FIRST(E) = { id }
• FIRST(E') = { +, ε }
• FOLLOW(E) = { $, ')' }
• FOLLOW(E') = { $, ')' }

Parsing Table

Non-terminal id + $

E E → T E'
Non-terminal id + $

E' E' → + T E' E' → ε

T T → id

🛠️ Parsing Process for input: id + id

Initial stack:
[E, $]
Input: id + id $

Steps:

1. Stack: E
Lookahead: id
Rule: E → T E'
2. Stack: T E'
Lookahead: id
Rule: T → id
3. Stack: id E'
Match id
Input becomes: + id $
4. Stack: E'
Lookahead: +
Rule: E' → + T E'
5. Stack: + T E'
Match +
Input becomes: id $
6. Stack: T E'
Lookahead: id
Rule: T → id
7. Stack: id E'
Match id
Input becomes: $
8. Stack: E'
Lookahead: $
Rule: E' → ε

✅ Input fully parsed — accepted.

✅ Key Advantages of Predictive Parsing

• No backtracking (efficient)
• Easy to implement (recursive or table-driven)
• Can be generated using tools or hand-written
❗ Limitation

• Only works for LL(1) grammars.


• Grammar must be left-factored and free from left recursion.
• Cannot handle more complex grammars (for those, bottom-up parsers like LR are used).

Difference between Shift-Reduce Parsing and Recursive Descent Parsing

These belong to different parsing families:

Feature Recursive Descent Parsing Shift-Reduce Parsing

Parsing Type Top-down Bottom-up

Left-to-right, constructs parse tree Left-to-right, constructs parse tree from


Direction
from root to leaves leaves to root

Uses recursive functions for each Uses a stack to shift input symbols and
Approach
non-terminal reduce by production rules

Grammar
LL grammars (predictive) LR grammars (more powerful)
Supported

May involve backtracking (unless


Backtracking No backtracking
LL(1))

Simple compilers, hand-written


Used In Parser generators (YACC, Bison)
parsers

Control Flow Explicit in code (recursive calls) Driven by parsing table or stack actions

2022
Q.3 (a) What is the role of a parser in compilation process?

Ans- Same as 2021 Q.3 (A)

(b) What does ambiguity in a context free grammar mean?

Ans- Same as 2021 Q.3 (b)

(c) How do you represent an abstract syntax tree ?

Ans- Same as 2021 Q.3 (A)

Q.4 (a) Why are Recursive Descent and LL parsers known as top-down parsers? How is left recursion
eliminated ?

Ans- Top-Down Parsing means:

• Parsing starts from the start symbol of the grammar.


• The parser predicts or chooses which productions to apply to eventually match the input
tokens.
• It constructs the parse tree from the root down to the leaves.

Recursive Descent Parsing

• Implements each non-terminal as a separate recursive function.


• These functions call each other according to the grammar rules.
• The process mimics the structure of the parse tree — from top (start symbol) to bottom
(terminals).

LL Parsers (LL(1), LL(k))

• L = Scan input Left to right


• L = Construct a Leftmost derivation
• The parser builds the parse tree top-down, using one (or k) lookahead tokens to guide
decisions.
• LL parsers can be implemented as recursive descent or table-driven (predictive parsing).

🔁 How is Left Recursion Eliminated?

What is Left Recursion?

A grammar is left recursive if a non-terminal recursively refers to itself on the left side of a
production.

Example:

A → Aα | β

This causes problems for top-down parsers, especially recursive descent, because they can go into
infinite recursion.

Types of Left Recursion:

1. Immediate Left Recursion:


Example: A → A + id | id
2. Indirect Left Recursion:
Example:

A → B α
B → A β | γ

✅ Eliminating Immediate Left Recursion

Given a production:
A → Aα | β

Transform it to:

A → β A'
A' → α A' | ε

Example:

Original (left-recursive):

E → E + T | T

After eliminating left recursion:

E → T E'
E' → + T E' | ε

Now the grammar is suitable for LL(1) or recursive descent parsing.

✅ Eliminating Indirect Left Recursion

1. Rearrange the non-terminals in some order.


2. For each non-terminal, replace its indirect recursion with its definitions.
3. Then eliminate any immediate recursion using the above method.

It’s more complex than immediate recursion removal and often requires systematic substitution.

(b) What is shift-reduced parsing ? Describe how LR parsers use the shift-reduce technique?
What is an LR Parser?

An LR parser is a type of bottom-up parser used to analyze a source code's syntax. It works by:

• Scanning input Left to right


• Producing a Rightmost derivation in reverse

Hence the name L-R.

🛠️ What is Shift-Reduce Parsing?

Shift-Reduce Parsing is the core method used by LR parsers. It involves two key actions:

1. Shift:
o Push (shift) the next input symbol onto the parsing stack.
o Do this when not enough information is available to reduce.
2. Reduce:
o Replace a string of grammar symbols on the stack (matching the right-hand side of a
production) with the corresponding non-terminal (left-hand side of the rule).
o This represents applying a grammar rule in reverse.

🔁 How the LR Parser Works

The parser uses:

• A stack to store symbols and parser states


• An input buffer containing the string to parse
• A parsing table with:
o ACTION table (Shift, Reduce, Accept, Error)
o GOTO table (used after a reduce)

Stack and Input Example

Let’s parse the string: id + id

With a sample grammar:

1. E → E + T
2. E → T
3. T → id

And sample parsing actions:


Parsing Process

✅ The string id + id is successfully parsed!

📌 Key LR Actions Summary


Action Description

Shift Push input symbol and new state onto stack

Reduce Apply a grammar rule in reverse, replace RHS with LHS

Goto After reduction, move to a new state based on non-terminal

Accept Input successfully parsed

Error Input does not conform to grammar

🧠 Why Use Shift-Reduce Parsing in LR Parsers?

• Very powerful: Can handle a wide range of grammars (LR(0), SLR, LALR, CLR).
• Efficient: No backtracking.
• Systematic: Uses a parsing table for decisions.
• Used in parser generators like YACC, Bison, etc.
2023
Q.3 (a) What is parsing? Explain top, down and bottom up parsing with the help of example.

Ans- What is Parsing in Compiler Design?

Parsing is the process of analyzing a sequence of input tokens (from the lexical analyzer) to
determine their grammatical structure according to a given grammar (usually a Context-Free
Grammar or CFG).

Purpose of Parsing

• To check whether the source code syntax is correct.


• To construct a parse tree or abstract syntax tree representing the program structure.
• Parsing is part of the syntax analysis phase of a compiler.

🔰 Types of Parsing Techniques

There are two main categories of parsing:

1. Top-Down Parsing

2. Bottom-Up Parsing

1⃣ Top-Down Parsing

In Top-Down Parsing, parsing starts from the start symbol of the grammar and tries to derive the
input string by applying productions from top (root) to bottom (leaves).

Examples of Top-Down Parsers:

• Recursive Descent Parser


• Predictive Parser (LL Parser)

How it Works:

• It expands the start symbol using the production rules.


• It uses lookahead tokens to decide which production to apply.
• If it finds a matching derivation, the input is accepted.

Example:
Consider the grammar:

r
CopyEdit
E → T + E | T
T → id

Input string: id + id

Derivation (Leftmost):

bash
CopyEdit
E
→ T + E
→ id + E
→ id + T
→ id + id

This builds the parse tree top-down, starting from E.

2⃣ Bottom-Up Parsing

In Bottom-Up Parsing, parsing starts from the input string (tokens) and reduces it to the start
symbol using the grammar in reverse order.

Examples of Bottom-Up Parsers:

• LR Parser
• SLR, LALR, CLR Parsers
• Shift-Reduce Parser

How it Works:

• It scans the input from left to right.


• It uses a stack to hold symbols.
• It performs two main operations:
o Shift: Push the next input symbol to the stack.
o Reduce: Replace the stack’s top items (matching RHS of a rule) with the LHS non-
terminal.

Example:

Same grammar:

r
CopyEdit
E → T + E
E → T
T → id
Input: id + id

Reductions (Rightmost derivation in reverse):

1. Shift id
2. Reduce id → T
3. Reduce T → E
4. Shift +
5. Shift id
6. Reduce id → T
7. Reduce E + T → E

✅ Reduced to E, so input is accepted.

🔍 Comparison: Top-Down vs Bottom-Up Parsing


Feature Top-Down Parsing Bottom-Up Parsing

Starts From Start Symbol Input string

Derivation Type Leftmost derivation Rightmost derivation in reverse

Parser Types LL, Recursive Descent LR, SLR, LALR, CLR

Backtracking May require (except LL(1)) No backtracking

Grammar Restrictions Cannot handle left recursion Can handle a larger class of CFGs

Stack Usage Implicit in recursion or manual Explicit stack (symbols + states)

Implementation Easier to implement by hand Used in parser generators (YACC)

🎯 Conclusion

• Parsing is essential for syntax checking and tree generation in compilers.


• Top-down parsers try to build the tree from the root, predicting what comes next.
• Bottom-up parsers reduce the input back to the root, confirming what was already seen.
• Choice depends on the grammar and desired complexity of the parser.

(b) E → T

T→T*F

T→ id

F→T

F → id
Draw parse tree representation of above expression for id*id.

Ans-

Q.4 What is LALR(1) parsing? Draw DFA and parsing table for the following equation :

S → AA

A → aA

A→b

Ans- What is LALR(1) Parsing?

LALR(1) stands for Look-Ahead LR parser with 1 token of lookahead. It is a type of bottom-up
parser that:

• Combines the simplicity of SLR(1) with the power of Canonical LR(1).


• Is widely used in parser generators like YACC, Bison, etc.

🔍 Key Features of LALR(1):


Feature Description

L Reads input Left to right

A Constructs a Rightmost derivation in reverse

LR(1) Uses 1 lookahead symbol to decide parsing action

LALR Merges similar LR(1) states (same core items) to reduce DFA size

Advantage Smaller parsing tables than Canonical LR(1), but more powerful than SLR(1)
📘 Grammar Given:
S → AA
A → aA
A → b

We’ll build:

1. Augmented Grammar
2. LR(0) Items
3. DFA of Canonical Collection
4. LALR(1) Parsing Table

1️⃣ Augmented Grammar

We add a new start symbol S':

0. S' → S
1. S → A A
2. A → a A
3. A → b

2️⃣ LR(0) Items and DFA

We construct the canonical LR(0) collection of items.

I0: Closure of S' → .S

S' → .S
S → .A A
A → .a A
A → .b

From I0:

• on S → I1
• on A → I2
• on a → I3
• on b → I4

I1:

S' → S.

I2:

S → A . A
A → .a A
A → .b
Transitions:

• on A → I5
• on a → I3 (same as before)
• on b → I4 (same as before)

I3:

A → a . A
A → .a A
A → .b

Transitions:

• on A → I6
• on a → I3
• on b → I4

I4:

A → b .

I5:

S → A A .

I6:

A → a A .
4️⃣ LALR(1) Parsing Table

We build the ACTION and GOTO table using these states and follow sets.

Terminals: a, b, $

Non-terminals: S, A

We'll assign numbers:

• 0 → I0
• 1 → I1
• 2 → I2
• 3 → I3
• 4 → I4
• 5 → I5
• 6 → I6

FOLLOW Sets

From the grammar:

• FOLLOW(S) = { $ }
• FOLLOW(A) = { a, b, $ } (since A appears in S → A A, and in recursive rule)
Notation Key

• sN: shift and go to state N


• rN: reduce using production N
• acc: accept

✅ Final Notes

• The LALR parser merges states with same LR(0) core but different lookaheads.
• This LALR(1) table handles the grammar efficiently without large parsing tables like canonical
LR(1).

2024
Q.3 (a) What do you mean by ambiguity in Context free grammar and write the steps to remove the
ambiguity in CFG by taking an appropriate example?

Ans- A Context-Free Grammar (CFG) is said to be ambiguous if at least one string in the
language generated by the grammar has more than one parse tree or more than one
leftmost or rightmost derivation.

Why is ambiguity a problem?

• Makes it unclear which structure a string represents.


• Compilers can't generate a unique syntax tree.
• Ambiguous grammars can lead to misinterpretation of programming language
constructs (e.g., if-else statements).

Example of an Ambiguous Grammar


E → E + E
E → E * E
E → ( E )
E → id

Input string: id + id * id

This grammar allows multiple parse trees:

1. One with + having lower precedence than *:

E → E + E
→ id + (id * id)
2. One with + having higher precedence than *:

E → E * E
→ (id + id) * id

✅ This is ambiguous because the same string gives multiple valid interpretations.

✅ How to Remove Ambiguity in CFG

To remove ambiguity, you can follow these steps:

✨ Step-by-Step Process

Step 1: Identify the Ambiguous Rules

Analyze the grammar and locate productions that can result in multiple parse trees or
derivations.

Step 2: Define Precedence and Associativity

Specify:

• Which operators have higher precedence (e.g., * > +)


• Which operators are left or right associative (e.g., + is left-associative)

Step 3: Rewrite the Grammar

Use non-terminals to encode precedence and associativity explicitly.

Example: Removing Ambiguity from Expression Grammar

Original Ambiguous Grammar:

E → E + E
E → E * E
E → ( E )
E → id

✅ Unambiguous Grammar (with * > + and both left-associative):

E → E + T | T
T → T * F | F
F → ( E ) | id
• Thandles higher-precedence *
• Ehandles lower-precedence +
• Left associativity is enforced by placing the recursive rule on the left

✅ Derivation with Unambiguous Grammar for id + id * id:

E
→ E + T
→ T + T
→ F + T
→ id + T
→ id + T * F
→ id + F * F
→ id + id * id

✅ Only one parse tree possible ⇒ grammar is unambiguous

(b) Explain TOP down parsing by taking an appropriate example.

Ans- Same as 2023 Q.3 (a)

Q.4 What do you mean by LALR parser? Design a LALR (1) Parsing table from the following
Grammar?

S -> AA

A -> aA

A -> b
LALR(1) stands for Look-Ahead LR parser with 1 lookahead symbol. It is a type of bottom-up parser
that combines:

• The precision of Canonical LR(1)


• The compactness of SLR
Key Concepts

Term Meaning

L Scans input Left to right

A Produces a Rightmost derivation in reverse

LR(1) Uses 1 token lookahead for decisions

LALR Merges LR(1) states with same LR(0) core

📘 Grammar Given:
S → A A
A → a A
A → b

We’ll create the LALR(1) Parsing Table for this grammar.

✅ Step-by-Step Construction of LALR(1) Table

1️⃣ Augment the Grammar

Add a new start symbol S':

0. S' → S
1. S → A A
2. A → a A
3. A → b

2️⃣ Construct the Canonical LR(0) Items

I0:

S' → .S
S → .A A
A → .a A
A → .b

Transitions from I0:

• On S → I1
• On A → I2
• On a → I3
• On b → I4

I1:

S' → S .

I2:

S → A . A
A → .a A
A → .b

Transitions:

• On A → I5
• On a → I3
• On b → I4

I3:

A → a . A
A → .a A
A → .b

Transitions:

• On A → I6
• On a → I3
• On b → I4

I4:

A → b .

I5:

S → A A .

I6:

A → a A .
4️⃣ Compute FOLLOW Sets

We use FOLLOW to determine lookaheads for reductions.

• FOLLOW(S) = { $ }
• FOLLOW(A) = { a, b, $ } (since A appears in S → A A)

5️⃣ Build LALR(1) Parsing Table

Terminals: a, b, $

Non-terminals: S, A

Actions:

• sN: shift and go to state N


• rN: reduce using production N
• acc: accept

You might also like