0% found this document useful (0 votes)
13 views16 pages

Unit Ii QB

compiler design question bank

Uploaded by

Jeeva R
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)
13 views16 pages

Unit Ii QB

compiler design question bank

Uploaded by

Jeeva R
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/ 16

Unit-II

Part- A
1. Consider the following grammar and demonstrate that the grammar is ambiguous
by showing two different parse trees for some string. (Nov/Dec 2020)
S→ AB |aaB
A→ a|Aa
B→b

For String “aab”


S->AB S->aaB
S->AaB S->aab
S->aaB
S->aab

2. Consider the following grammar: (Nov/Dec 2020)


S→ A
A→ A+ A|B++
B→y
Show a leftmost and rightmost derivation for the string “y + + + y + +”.
LMD
S->A
S->A+A
S->B+++A
S->y+++A
S->y+++B++
S->y+++y++
RMD
S->A
S->A+A
S->A+B++
S->A+y++
S->B+++y++
S->y+++y++

3. Eliminate the left recursion for the grammar (Nov/Dec 2020)


S→ A a | b
A→ Ac | S d |∈

A->SdA`
A`->cA`|∈
4. What is meant by coercion? (Nov/Dec 2020)
The Argument Coercion is one technique by which the compiler can implicitly
convert the arguments from one type to another type. It follows argument promotion
rule. If one argument is lower datatype, that can be converted into higher datatypes, but
the reverse is not true.

5. Draw syntax tree for the expression a = b* – c + b* – c. (Nov/Dec 2020)


6. What are the different stages that a parser can recover from syntactic error? (Nov/Dec
2018)
Panic mode recovery is used to handle syntax errors by the parser. In panic mode
recovery, as soon as the compiler discovers a syntax error, it enters panic mode. As a
result, it starts to discard the input string until it finds a symbol from which it can resume
its normal operation.

7. Define LR(0) item. (Nov/Dec 2018)


An LR(0) item is a production of the grammar with exactly one dot on the right-
hand side. For example, production T → T * F leads to four LR(0) items: T → ⋅ T * F.

8. What is bottom up parsing and shift reduce parsing? (Nov/Dec 2020)


Shift Reduce Parser is a type of Bottom-Up Parser. It generates the Parse Tree
from Leaves to the Root. In Shift Reduce Parser, the input string will be reduced to the
starting symbol. This reduction can be produced by handling the rightmost derivation
in reverse, i.e., from starting symbol to the input string.

9. List out the steps performed for LR parsing. (April/May 2022)


 For the given input string write a context free grammar.
 Check the ambiguity of the grammar.
 Add Augment production in the given grammar.
 Create Canonical collection of LR (0) items.
 Draw a data flow diagram (DFA).
 Construct a LR (1) parsing table.

10. What is an ambiguous grammar? Give an example. (Nov/Dec 2020)


A grammar is said to be ambiguous if there exists more than one leftmost
derivation or more than one rightmost derivation or more than one parse tree for the
given input string. If the grammar is not ambiguous, then it is called unambiguous.

11. Show that the grammar S->aSbS|bSaS|∈ is ambiguous (Nov/Dec 2019)


S->aSbS S->aSbS
S->a∈bS S->abSaSbS
S->abbSaS S->abbSaSaSbS
S->abb∈aS S->abb∈aSaSbS
S->abbaaSbS S->abba∈aSbS
S->abbaa∈bS S->abbaa∈bS
S->abbaab∈ S->abbaab∈
S->abbaab S->abbaab
12. Give the structure of YACC program to design a simple lexical analyser. (Nov/Dec
2019)
Structure
/* definitions */
....

%%
/* rules */
....
%%

/* auxiliary routines */
....

13. What do you mean by handle pruning? (April/May 2019)


 The handle is the substring that matches the body of a production whose
reduction represents one step along with the reverse of a Rightmost derivation.

 The handle of the right sequential form Y is the production of Y where the string
S may be found and replaced by A to produce the previous right sequential form
in RMD(Right Most Derivation) of Y.
 Sentential form: S => a here, ‘a’ is called sentential form, ‘a’ can be a mix of
terminals and nonterminals.

14. Mention the purpose of YACC. (April/May 2019)


YACC provides a tool to produce a parser for a given grammar. YACC is a
program designed to compile a LALR (1) grammar. It is used to produce the source
code of the syntactic analyzer of the language produced by LALR (1) grammar.

15. Define the function left factoring. (Nov/Dec 2021)


Left factoring is a process by which the grammar with common prefixes is
transformed to make it useful for Top down parsers. This kind of grammar creates a
problematic situation for Top down parsers. Top down parsers can not decide which
production must be chosen to parse the string in hand.

16. How do you identify predictive parser and non-recursive predictive parser? (Nov/Dec
2021)
 Predictive parsing is a special form of recursive descent parsing, where no
backtracking is required, so this can predict which products to use to replace the
input string.
 Non-recursive predictive parsing or table-driven is also known as LL(1) parser.
This parser follows the leftmost derivation (LMD).

17. For what type of grammar, recursive descent parser cannot be constructed? Show the
steps involved in recursive descent parsing with backtracking for the string cad with
the given grammar S->cAd, A->ab|a (April/May 2023)
S->cAd
S->cad
The above grammar has no left recursion.
18. Construct a parse tree and syntax tree for 4-6/3*5+7 (April/May 2023)

19. Compare syntax tree and parse tree (Nov/Dec 2017)


 A parse tree is created by a parser, which is a component of a compiler that
processes the source code and checks it for syntactic correctness.
 A syntax tree is created by the compiler based on the parse tree after the parser
has finished processing the source code.

20. Construct parse tree for -(id+id)

21. What are the goals of error handler in a parser? (Nov/Dec 2023)
The goals of an error handler in a parser are:
1. Detection of Errors: Identify syntactical errors in the source code as early as possible.
2. Recovery from Errors: Attempt to recover from errors so that parsing can continue and
more errors can be detected in a single pass.
3. Reporting Errors:** Provide meaningful and clear error messages that help the
programmer understand the nature and location of the errors.
4. Preserving the Parsing Process:** Ensure that the parser continues to operate correctly
and reaches a valid conclusion, even after encountering errors.
5. Minimizing the Impact of Errors: Prevent cascading errors by correcting or ignoring
errors in a way that minimizes their impact on the rest of the parsing process.

22. Define a parse tree (Nov/Dec 2023)


A parse tree, also known as a syntax tree, is a hierarchical tree structure that
represents the syntactic structure of a string according to a formal grammar. Each node
in the tree corresponds to a construct occurring in the source code, with the root
representing the start symbol of the grammar and the leaves representing the input
tokens. The interior nodes represent the application of production rules that generate
the input string, showing how the string can be derived from the grammar. Parse trees
are used in compilers and interpreters to check the correctness of the syntax of the input
and to guide the translation of the code into machine-readable form.
Part- B
1. Consider the following grammar. Parse the input string “abbcde” using stack
implementation of shift-reduce parser. (Nov/Dec 2020)
S→ aABe
A→ Abc | b
B→d

Parsing Table
a b c d e $ S A B
0 S2 S4 S5 1 3
1 Accept
2 S4 6,3
3 S7
4 r3 r3
5 r4
6 S5 8
7 S9
8 S10
9 r2 r2
10 r1
String abbcde
Stack Move of Input Tape Output

$S abbcde$ S->aABe

$eBAa abbcde$ pop

$eBA bbcde$ A->Abc


$eBcbA bbcde$ A->b

$eBcbb bbcde$ pop

$eBcb bcde$ pop

$eBc cde$ pop

$eB de$ B->d

$ed de$ pop

$e e$ pop

$ $ Accept

2. Construct LL(1) parsing table for the following grammar using FIRST and
FOLLOW set. (Nov/Dec 2020)
S→ UVW
U→ (S) | aSb |d
V → aV| e
W → cW | e
Give the parsing actions for the input string “(dc)ac”.

First and Follow


First Follow
S {(,a,d} {).$,b}
U {(,a,d} {a,e}
V {a,e} {c,e}
W {c.e} {).$,b}

Parsing Table

( ) a d b c e $
S S->UVW S->UVW S->UVW
U U->(S) U->aSb U->d
V V->aV V->e
W W->cW W->e

String (dc)ac
Stack Move of Input Tape Output

$S (dc)ac$ S->UVW

$WVU (dc)ac$ U->(S)

$WV)S( (dc)ac$ pop

$WV)S dc)ac$ S->UVW


$WV)WVU dc)ac$ U->d

$WV)WVd dc)ac$ pop

$WV)WV c)ac$ Not matched


String cannot be parsed.

3. Construct a predictive parser for the following grammar. (Nov/Dec 2020) (April/May
2022) (Nov/Dec 2021)
S → (L) | a
L→ L, S | S. String (a,(a,(a,a)))

Remove Left recursion


L->L,S|S

L->SL’
L’->,SL’|∈

The productions are


S → (L) | a
L->SL’
L’->,SL’|∈
First and Follow
First Follow
S {(,a} {),$}
L {(,a} {)}
L’ {,,∈} {)}

Parsing Table
( ) a , $

S S -> (L) S -> a

L L -> SL’ L -> SL’

L’ L’ -> ε L’ -> ,SL’

String (a,(a,(a,a)))
Stack Move of Input Tape Output

$S (a,(a,(a,a)))$ S->(L)

$)L( (a,(a,(a,a)))$ pop

$)L a,(a,(a,a)))$ L->SL’


$)L’S a,(a,(a,a)))$ S->a

$)L’a a,(a,(a,a)))$ pop

$)L’ ,(a,(a,a)))$ L’->,SL’

$)L’S, ,(a,(a,a)))$ pop

$)L’S (a,(a,a)))$ S->(L)

$)L’)L( (a,(a,a)))$ pop

$)L’)L a,(a,a)))$ L->SL’

$)L’)L’S a,(a,a)))$ S->a

$)L’)L’a a,(a,a)))$ pop

$)L’)L’ ,(a,a)))$ L’->,SL’

$)L’)L’S, ,(a,a)))$ pop

$)L’)L’S (a,a)))$ S->(L)

$)L’)L’)L( (a,a)))$ pop

$)L’)L’)L a,a)))$ L->SL’

$)L’)L’)L’S a,a)))$ S->a

$)L’)L’)L’a a,a)))$ pop

$)L’)L’)L’ ,a)))$ L’->,SL’

$)L’)L’)L’S, ,a)))$ pop

$)L’)L’)L’S a)))$ S->a

$)L’)L’)L’a a)))$ pop

$)L’)L’)L’ )))$ L’->∈

$)L’)L’) )))$ pop

$)L’)L’ ))$ L’->∈

$)L’) ))$ pop

$)L’ )$ L’->∈

$) )$ pop

$ $ Accept
4. Explain the operator precedence parsing with suitable example. (Nov/Dec 2020)
Operator precedence grammar is kinds of shift reduce parsing method. It is
applied to a small class of operator grammars. A grammar is said to be operator
precedence grammar if it has two properties:
 No R.H.S. of any production has a∈.
 No two non-terminals are adjacent.
Operator precedence can only established between the terminals of the grammar. It
ignores the non-terminal.
There are the three operator precedence relations:
 a ⋗ b means that terminal "a" has the higher precedence than terminal "b".
 a ⋖ b means that terminal "a" has the lower precedence than terminal "b".
 a ≐ b means that the terminal "a" and "b" both have same precedence.

Precedence table:

Parsing Action
 Both end of the given input string, add the $ symbol.
 Now scan the input string from left right until the ⋗ is encountered.
 Scan towards left over all the equal precedence until the first left most ⋖ is
encountered.
 Everything between left most ⋖ and right most ⋗ is a handle.
 $ on $ means parsing is successful

5. Consider the following grammar and construct predictive parser. (Nov/Dec 2019)
E → E + T/T, T → T * F|F, F → (E) |id.
Check id+id*id

First and Follow


First Follow

E –> TE’ { id, ( } { $, ) }

E’ –> +TE’/ε { +, ε } { $, ) }

T –> FT’ { id, ( } { +, $, ) }

T’ –> *FT’/ε { *, ε } { +, $, ) }
First Follow

F –> id/(E) { id, ( } { *, +, $, ) }

Parsing Table
id + * ( ) $

E E –> TE’ E –> TE’

E’ E’ –> +TE’ E’ –> ε E’ –> ε

T T –> FT’ T –> FT’

T’ T’ –> ε T’ –> *FT’ T’ –> ε T’ –> ε

F F –> id F –> (E)

String “id+id*id”
Stack Move of Input Tape Output

$E id + id * id $ E → T E'
$ E' T id + id * id $ T → FT'
$ E' T ' F id + id * id $ F → id
$ E' T ' id id + id * id $ POP
$ E' T ' + id * id $ T'→
$ E' + id * id $ E' → + T E'

$ E' T + + id * id $ POP
$ E' T id * id $ T → FT'
$ E' T ' F id * id $ F → id
$ E' T ' id id * id $ POP
$ E' T ' * id $ T '→ * F T '
$ E' T ' F * * id $ POP
$ E' T ' F id $ F → id
$ E' T ' id id $ POP
$ E' T ' $ T'→
$ E' $ E'→
$ STRING
$ ACCEPTED

6. Explain the usage of YACC parser generator in construction of a parser with one
example. (April/May 2023)
Each translation rule input to YACC has a string specification that resembles a
production of a grammar-it has a nonterminal on the LHS and a few alternatives on the
RHS. For simplicity, we will refer to a string specification as a production. YACC
generates an LALR(1) parser for language L from the productions, which is a bottom-
up parser. The parser would operate as follows: For a shift action, it would invoke the
scanner to obtain the next token and continue the parse by using that token. While
performing a reduced action in accordance with production, it would perform the
semantic action associated with that production.

The semantic actions associated with productions achieve the building of an


intermediate representation or target code as follows:

Every nonterminal symbol in the parser has an attribute.


The semantic action associated with a production can access attributes of nonterminal
symbols used in that production–a symbol “$n’ in the semantic action, where n is an
integer, designates the attribute of the nonterminal symbol in the RHS of the production
and the symbol ‘$$’ designates the attribute of the LHS nonterminal symbol of the
production.
The semantic action uses the values of these attributes for building the intermediate
representation or target code.
A parser generator is a program that takes as input a specification of a syntax and
produces as output a procedure for recognizing that language. Historically, they are also
called compiler compilers. YACC (yet another compiler-compiler) is an LALR(1)
(LookAhead, Left-to-right, Rightmost derivation producer with 1 lookahead token)
parser generator. YACC was originally designed for being complemented by Lex.

Input File: YACC input file is divided into three parts.


1. Definition part
2. Rule part
3. Auxilary Routines part

Structure
/* definitions */
....

%%
/* rules */
....
%%

/* auxiliary routines */
....
Input File: Definition Part:

The definition part includes information about the tokens used in the syntax definition:
%token NUMBER
%token ID
Yacc automatically assigns numbers for tokens, but it can be overridden by
%token NUMBER 621
Yacc also recognizes single characters as tokens. Therefore, assigned token numbers
should no overlap ASCII codes.
The definition part can include C code external to the definition of the parser and
variable declarations, within %{ and %} in the first column.
It can also include the specification of the starting symbol in the grammar:
%start nonterminal

Input File: Rule Part:

The rules part contains grammar definitions in a modified BNF form.


Actions is C code in { } and can be embedded inside (Translation schemes).
Input File: Auxiliary Routines Part:

The auxiliary routines part is only C code.


It includes function definitions for every function needed in the rules part.
It can also contain the main() function definition if the parser is going to be run as a
program.
The main() function must call the function yyparse().
Input File:

If yylex() is not defined in the auxiliary routines sections, then it should be included:
#include "lex.yy.c"
YACC input file generally finishes with:
.y

Output Files:

The output of YACC is a file named y.tab.c


If it contains the main() definition, it must be compiled to be executable.
Otherwise, the code can be an external function definition for the function int yyparse()
If called with the –d option in the command line, Yacc produces as output a header file
y.tab.h with all its specific definition.
If called with the –v option, Yacc produces as output a file y.output containing a textual
description of the LALR(1) parsing table used by the parser.

Example: Yacc File (.y)

%{
#include <ctype.h>
#include <stdio.h>
#define YYSTYPE double /* double type for yacc stack */
%}
%%
Lines : Lines S '\n' { printf("OK \n"); }
| S '\n’
| error '\n' {yyerror("Error: reenter last line:");
yyerrok; };
S : '(' S ')’
| '[' S ']’
| /* empty */ ;
%%

#include "lex.yy.c"

void yyerror(char * s)
/* yacc error handler */
{
fprintf (stderr, "%s\n", s);
}

int main(void)
{
return yyparse();
}
Lex File (.l)

%{
%}

%%
[ \t] { /* skip blanks and tabs */ }
\n|. { return yytext[0]; }
%%
7. Explain LL(1) grammar for the sentence (April/May 2023)
S->iEts|iEtSeS|a
E->b

After left factoring


S->iEtSS`|a
S`->eS| ε
E->b
First and Follow
First Follow
S i,a e,$
S` e, ε e,$
E b t

Parsing Table
i a e b $
S S->iEtSS S->a
S` S`->eS
S`-> ε
E E->b

Since there are more than one production for an entry in the table, the grammar is not
LL(1) grammar.

8. Briefly discuss about Design of a syntax analyzer for a sample language. (Nov/Dec
2023)
Defining the Grammar:
 Start by defining the formal grammar of the language, typically using a
context-free grammar (CFG). The grammar consists of a set of production
rules that describe the syntax of valid statements in the language. For example,
a simple arithmetic expression grammar might include rules like:
expr → expr + term | term
term → term * factor | factor
factor → ( expr ) | number

Choosing the Parsing Technique:


 Decide whether to use a top-down or bottom-up parsing approach.
 Top-down parsers (like LL parsers) start from the start symbol and try to
rewrite it to match the input string.
 Bottom-up parsers (like LR parsers) start from the input string and attempt to
reduce it to the start symbol.
 For simple languages, a recursive descent parser (a type of top-down parser) is
often used because it is easier to implement and understand.

Lexical Analysis Integration:


 Before syntax analysis, integrate a lexical analyzer (lexer) that tokenizes the
input source code into a sequence of tokens (like keywords, operators,
identifiers, etc.). These tokens are the input to the parser.

Parser Implementation:
 Implement the parser using the chosen technique. For a recursive descent
parser, write a set of recursive functions corresponding to each non-terminal in
the grammar. These functions call each other according to the production rules
to match the input tokens.
 For example, a function parseExpr() might recursively call parseTerm()
and handle the "+" operation by matching tokens and building the parse tree.

Error Handling:
Implement error detection and recovery mechanisms. The parser should be
able to detect syntax errors and recover gracefully to continue parsing subsequent
parts of the input.
Building the Parse Tree:
As the parser processes the input, it can build a parse tree that represents the
syntactic structure of the code. This tree can later be used for further processing, such
as semantic analysis or code generation.

Testing with Sample Inputs:


Test the syntax analyzer with sample inputs to ensure it correctly recognizes
valid syntax and rejects invalid syntax according to the grammar rules.

9. Explain the LR parsing algorithm with an example. (Nov/Dec 2023)


A schematic of an LR parser is shown in Figure 10. It consists of an input, an
output, a stack, a driver program, and a parsing table that has two pasts (ACTION
and GOTO). The driver program is the same for all LR parsers; only the parsing table
changes from one parser to another. The parsing program reads characters from an
input buffer one at a time. Where a shift-reduce parser would shift a symbol, an LR
parser shifts a state. Each state summarizes the information contained in the stack
below it.
The stack holds a sequence of states, s0s1…sm where sm, is on top. In the SLR
method, the stack holds states from the LR(0) automaton; the canonical- LR and
LALR methods are similar.

Structure of the LR Parsing Table


The parsing table consists of two parts: a parsing-action function ACTION and a
goto function GOTO.
1. The ACTION function takes as arguments a state i and a terminal a (or $, the
input end marker). The value of ACTION[i, a] can have one of four forms:
(a) Shift j, where j is a state. The action taken by the parser effectively shifts
input a to the stack, but uses state j to represent a.
(b) Reduce A β. The action of the parser effectively reduces β on the top of
the stack to head A.
(c) Accept. The parser accepts the input and finishes parsing.
(d) Error. The parser discovers an error in its input and takes some corrective
action.
2. We extend the GOTO function, defined on sets of items, to states: if GOTO[Ii,
A] = Ij, then GOTO also maps a state i and a nonterminal A to state j.

Algorithm : LR-parsing algorithm.


INPUT: An input string w and an LR-parsing table with functions ACTION
and GOTO for a grammar G.
OUTPUT: If w is in L(G), the reduction steps of a bottom-up parse for w;
otherwise, an error indication.
METHOD: Initially, the parser has so on its stack, where so is the initial state,
and w$ in the input buffer.
let a be the first symbol of w$;
while(1)
{ /* repeat forever */
let s be the state on top of the stack;
if ( ACTION[S, a] = shift t )
{
push t onto the stack;
let a be the next input symbol;
}
else if ( ACTION[S, a] = reduce A β)
{
pop | β| symbols off the stack;
let state t now be on
top of the stack;
push GOTO[t, A]
onto the stack;
output the
production A β;
}
else if ( ACTION[S, a] = accept ) break; /* parsing is done */
else call error-recovery routine;
}

You might also like