Professional Documents
Culture Documents
Compiler Ass
Compiler Ass
C++ is a compiled language and compiles directly to machine code, meaning that the code is linked
directly to the hardware and will run faster than Java. Java is a bytecode language which compiles to
bytecode and runs on the JVM, meaning it is platform-independent and slower than C++.
2. Write the algorithm of predictive parsing using tables and parse x-2*y using top down
Algorithm:
1. Construct a parse table containing all possible terminal and non-terminal symbols, including the start
symbol
2. Using the parse table, form a parse tree containing all the terminal and non-terminal symbols
3. Choose any non-terminal from the root of the parse tree, enter it in the stack
4. Match the first symbol from the input string against the top of the stack
5. If the symbol is a terminal, Pop it from the stack & Match it with the same symbol from the input
string
6. If the symbol is a non-terminal, look up the corresponding productions in the parse table &
Push the symbols in the right side of the production into the stack in reverse order
7. Repeat steps 4-6 until all symbols in the stack and the input string are matched
F *y Pop F, Push F → * F
F *y Pop F, Push F → y
3. Explain how shift reduce parsing using ACTION/GOTO table is implemented using
example
2Shift-Reduce Parsing using ACTION/GOTO tables is a type of bottom-up parsing. It goes through a given
grammar and builds up the parse tree from the bottom up.
A Shift-Reduce Parser first looks at an input string and uses a set of Parser Actions to determine if the
string can be shifted (moved) to the right or reduced. When shifting, the parser moves the input string
one symbol to the right, and when reducing, the parser will try to match the symbols of the input string
with a part of the grammar and if it matches, it will replace the matched part of the input string with a
non-terminal and add to the parse tree.
Grammar:
Article → the
Noun → book
Verb → read
ACTION GOTO
----------------------------------------------------------------
----------------------------------------------------------------
1 S4 S5 - Goto 2 Goto 3 -
2 - S6 - - - -
3 - - S7 - - -
4 - - - - - Accept
5 - - - - - Reduce Noun
The parser will start in state 1. It will then take action corresponding to the symbol at the start of the
input string. In this case, the first symbol is ‘the’, and so the parser will shift to state 4. From state 4, the
parser will see the symbol ‘book’ and shift to state 5. From state 5, the parser will see the symbol ‘read’
and reduce Noun. This will replace the matched part of the input string (‘book read’) with a non-
terminal (‘NounPhrase’). The parser will then shift to state 6. From state 6, the parser will reduce Noun
Phrase and this will replace the matched part of the input string (‘the NounPhrase’) with a non-terminal
(‘VerbPhrase’). From state 3, the parser will shift to state 7 and then reduce Verb Phrase, replacing the
matched part of the input string (‘the VerbPhrase’) with the non-terminal (‘Sentence’). The parser will
then move to state 4 and accept the input string.
4𝐌𝐀: LALR (Look-Ahead LR) is a type of bottom-up parsing algorithm that is similar to LR (Left-to-Right)
parsing, but with a smaller parsing table. LALR uses look-ahead symbols to disambiguate between
different grammar rules and reduce the size of the parsing table, making it more practical to use in real-
world applications.
1. Construct a parse table from the given grammar. The parse table has two parts: a state transition
table (GOTO) and an action table. The GOTO table is used to determine which state to transition to after
shifting a symbol onto the stack, and the action table is used to determine whether to shift or reduce at
each step.
2. Initialize a stack and a current position in the input string. Push the initial state (0) onto the stack and
set the current position to the beginning of the input string.
3. Look up the current symbol in the input string and the top state on the stack in the action table.
4. If the entry in the action table is "shift X", where X is a state, push the current symbol onto the stack
and transition to state X.
5. If the entry in the action table is "reduce A -> B C", where A, B, and C are grammar symbols, pop the
top two symbols (B and C) from the stack and replace them with symbol A. Then, look up A and the new
top state on the stack in the GOTO table and push the resulting state onto the stack.
6. Repeat steps 3-5 until the input string has been fully processed and the stack contains only the initial
state and the goal non-terminal symbol.
Here is an example of how the LALR algorithm might be used to parse the input string "2 + 3 * 4":
1. Construct the parse table from the given grammar. The GOTO table might contain the following
entries:
- GOTO0, E = 6
- GOTO6, T = 7
- GOTO7, F = 8
- GOTO8, \* = 9
- GOTO9, F = 10
- GOTO6, F = 11
- GOTO7, + = 12
- GOTO12, T = 13
- GOTO13, F = 14
- GOTO14, \* = 15
- GOTO15, F = 16
- ACTION0, 2 = shift 3
- ACTION3, + = shift 5
- ACTION5, 2 = shift 3
- ACTION3, \* = shift 6
- ACTION6, 2 = shift 3
- ACTION6, 2 = shift 3
Item-set construction is a technique used in the construction of LR parsing tables. Given a context-free
grammar, the goal of item-set construction is to create a set of "items" that represent the possible steps
of a parse, and to group these items into sets called "item sets".
1. Begin with the set of all grammar rules, and create a single item set containing the items "A -> alpha .
B beta", where A is a non-terminal symbol, alpha is a sequence of symbols, and beta is a sequence of
symbols. These items represent the possible steps in a parse, with the "dot" symbol (.) indicating the
current position in the rule.
- For each item of the form "A -> alpha . B beta" in the item set, add the item "B -> . gamma" for each
production rule "B -> gamma" in the grammar.
- For each item of the form "A -> alpha B . beta" in the item set, add the item "B -> gamma . delta" for
each production rule "B -> gamma delta" in the grammar.
3. Repeat step 2 until no new items can be added to any item set.
Here is an example of how item-set construction might be carried out for the grammar:
E -> E + T
E -> T
T -> T * F
T -> F
F -> (E)
F -> id
1. Begin with the set of all grammar rules, and create a single item set containing the following items:
- E -> . E + T
- E -> . T
- T -> . T * F
- T -> . F
- F -> . (E)
- F -> . id
- For each item of the form "A -> alpha . B beta" in the item set, add the item "B -> . gamma" for each
production rule "B -> gamma" in the grammar.
- For each item of the form "A -> alpha B . beta" in the item set, add the item "B -> gamma . delta" for
each production rule "B -> gamma delta" in the grammar.
Item set 1:
- E -> . E + T
- E -> . T
- T -> . T * F
- T -> . F
- F -> . (E)
- F -> . id
- T -> T . * F
- F -> ( . E )
- E -> E . + T
Item set 2:
- T -> T * . F
- F -> . (E)
- F -> . id
- E -> T .
- T -> F .
- F -> (E) .
- F -> id .
Item set 3:
- E -> E + T .
- T -> T * F .
- F -> (E) .
- F -> id .
Item set 4:
- F -> (E) .
- F -> id .
Item set 5:
- F -> (E) .
- F -> id .
Item set 6:
- F -> (
6. Discuss how conflicts are resolved during parsing(Example: shift-reduce conflict) give
example9
During parsing, conflicts can arise when the parser has to choose between two or more options for the
next step in constructing the parse tree. One common type of conflict is a shift-reduce conflict, which
occurs when the parser has to decide whether to shift the next token onto the stack (i.e., postponing its
reduction) or to reduce the current contents of the stack (i.e., combining them into a single unit).
Stack: 1 + 2
Here, the parser has to choose between shifting the next token (3) onto the stack or reducing the
current stack contents (1 + 2) to a single unit. The choice depends on the operator precedence: if * has
higher precedence than +, then the parser should reduce the stack contents to a single unit before
shifting 3 onto the stack. If + has higher precedence than *, then the parser should shift 3 onto the stack
before reducing the current stack contents.
In this case, the correct choice is to reduce the stack contents to a single unit, since * has higher
precedence than +. The resulting stack would be:
Stack: (1 + 2) * 3
This conflict can be resolved using operator precedence rules, which specify the order in which
operations should be performed. However, other conflicts may require more complex resolution
strategies, such as using context-sensitive rules or consulting a parse table
S->aBDh
B->cC
C->bC/ᵋ
D->EF
E->g/ᵋ
F->f/ᵋ10
𝐏𝐈: The first() function returns the set of terminal symbols that can begin a string derived from a given
non-terminal symbol. The follow() function returns the set of terminal symbols that can immediately
follow a given non-terminal symbol in some string derived from the grammar.
For this grammar, we can define the first() and follow() functions as follows:
first(S) = {a}
first(B) = {c}
first(C) = {b}
first(D) = {g, ε}
first(E) = {g, ε}
first(F) = {f, ε}
follow(S) = {$}
follow(B) = {h}
follow(C) = {c, h}
follow(D) = {h}
follow(E) = {f}
follow(F) = {h}
first(X) = {first(Y) | Y appears in the right-hand side of a production of the form X -> YZ}
first(X) = {ε} if X -> ε is a production, and X does not appear in the right-hand side of any other
production
follow(X) = {follow(Y) | Y appears in the right-hand side of a production of the form YZ -> X}
follow(X) = {first(Y) - {ε} | Y appears in the right-hand side of a production of the form XY -> XZ, and ε is
in first(Y)}
follow(S) = {$}
Using these rules, we can compute the first() and follow() sets for the given grammar as follows:
first(S) = {a}
first(B) = {c}
first(C) = {b}
first(D) = {g, ε}
first(E) = {g, ε}
first(F) = {f, ε}
follow(S) = {$}
follow(B) = {h}
follow(C) = {c, h}
follow(D) = {h}
follow(E) = {f}
follow(F) = {h}
A LL(1) parser is an efficient predictive parser that uses a top-down approach based on a set of Left-to-
right scan of the input with a single current input symbol and a single stack symbol. It parses the input
and produces a parse tree.
2. Building the Parsing Table: The next step is to build the parsing table. The parsing table contains
entries which link a non-terminal symbol to a terminal symbol in the grammar. Each of these entries
contains either a production rule to be used or an error indication.
3. Traversing the Parsing Table: The parsing table is then traversed in the same way as a normal LL(1)
parser would. The parser starts at the beginning symbol of the grammar, and follows the links in the
parsing table. If the parser encounters a terminal symbol, it marks it as visited. If the parser encounters a
non-terminal symbol, it uses that symbol's row in the parsing table to determine which production rule
to use.
4. Generating the Parse Tree: Finally, the parser uses the parse tree that it created while traversing the
parsing table to generate the parse tree. The parse tree is a recursive structure which contains the
assigned meanings to the non-terminal symbols. The parse tree is then used for generating the parse
code for the given input string.