LL(k) and LR(K) Grammars
Top-down and Bottom-up Parsers
LL(k) Grammars
• The term "LL(k) grammar" refers to a class of context-free grammars in
formal language theory.
• In the context of automata theory, LL(k) grammars are a subset of context-
free grammars that can be parsed by a certain type of parsing algorithm
called LL(k) parsing.
• L: Stands for Left-to-right scanning of the input.
• L: Stands for Leftmost derivation. This means that when constructing a
parse tree, the leftmost non-terminal symbol is always the one expanded
first.
• (k): The 'k' represents the number of look ahead symbols the parser uses
to make parsing decisions. In LL(k) parsing, the parser looks at 'k' symbols
of the input to decide which production to use.
• LL(k) grammars are a proper superset of the class of deterministic context-
free grammars (DCFGs).
• This means that all DCFGs are LL(k) for some value of k, but not all LL(k)
grammars are DCFGs.
• Parsing techniques like recursive descent parsing and table-driven LL(k)
parsing are commonly used for parsing LL(k) grammars.
• Let's consider a simple example of an LL(1) grammar. In this grammar, we
have terminals a and b, and a non-terminal S. The language generated by this
grammar consists of strings of as and bs, where each string starts with an a
and has zero or more bs. The LL(1) grammar for this language is as follows:
• S→aSb|a
• In this grammar:
• a and b are terminals.
• S is the non-terminal symbol
Example
S-> aA|b
If we want to generate string ab, it can be
clearly seen that it can be generated in 2
step. Hence the value of k is 2.
Properties of LL(k) Grammars
• Predictive Parsing: LL(k) grammars can be parsed using a top-down, left-to-right
parsing strategy with a lookahead of k symbols. This means that you can predict
the production to apply based on the current non-terminal and the next k input
symbols.
• Leftmost Derivation: LL(k) grammars are parsed using leftmost derivation, where
at each step, the leftmost non-terminal in the current production is expanded. This
property simplifies parsing and leads to efficient LL(k) parsers.
• No Backtracking: LL(k) parsers do not require backtracking. Once a production is
chosen, there is no need to undo or backtrack the parsing process. The parsing
decision is made deterministically based on the current symbol being parsed and
the lookahead symbols.
• LL(1) Grammars: A subset of LL(k) grammars is LL(1) grammars, where the parsing
decision is based on a single lookahead symbol (k=1). LL(1) grammars are
particularly useful because of their simplicity, and many programming languages
can be described by LL(1) grammars.
• Parsing Table: LL(k) grammars can be represented by a parsing table. This table
guides the parsing process by indicating which production to use for a given non-
terminal and lookahead symbol. If there are no conflicts in the table, the grammar
is LL(k).
• Ambiguity Resolution: LL(k) grammars are typically
unambiguous, meaning there is only one valid parse
tree for any given input string. Ambiguity can
complicate language understanding and compiler
design, and LL(k) grammars help avoid such ambiguity.
• Efficient Parsing: LL(k) parsing is efficient and can be
implemented without much complexity, making it
suitable for practical applications such as compilers
and interpreters. Recursive descent parsers and table-
driven parsers are common techniques used for LL(k)
parsing.
Limitations
• The LL(k) parsing method cannot handle all context-free grammars.
• There are certain grammars for which LL(k) parsers cannot be
constructed.
• This limitation is due to the fact that LL(k) parsers need to make parsing
decisions based on a fixed number of look ahead symbols, and some
grammars require an unlimited look ahead to parse correctly.
• Such grammars are termed LL(k) for some infinite k, denoted as LL(*).
• In practical terms, LL(1) grammars (grammars where the parsing decision
is made based on a single look ahead symbol) are commonly used in
compiler design and other areas where efficient parsing is essential due to
their simplicity and ease of implementation.
LR(K) Grammars
• LR(k) grammars are a class of context-free grammars that are
more powerful than LL(k) grammars. LR(k) parsers are capable
of parsing a larger set of grammars, including many
programming languages. In LR(k) parsing, 'L' stands for
scanning the input from left to right, 'R' stands for constructing
a rightmost derivation in reverse (hence, "LR"), and 'k'
represents the number of lookahead symbols used for making
parsing decisions.
• An LR(k) grammar allows an LR(k) parser to decide which
production to apply based on the current input symbol and k
lookahead symbols. These parsers can handle a broader range
of grammars than LL(k) parsers.
Example LR(k) Grammar:
• Consider the following grammar:
• S→AA
• A→aA/b
• In this grammar:
• a,b are terminals.
• S, A are non-terminal symbol.
• If we want to derieve W= bab
Properties of LR(k) Grammars
• Property 1 : Every LR(k) grammar G is unambiguous.
There exists a unique right-most derivation. Any pushdown automaton accepts a context-
free language and for any context-free language L, we can construct a pushdown automaton
accepting L.
• Property 2 If G is an LR(k) grammar. there exists a deterministic pushdown automaton A
accepting L(G).
• Property 3 If A is a deterministic pushdown automaton A, there exists an LR(l) grammar G
such that L(G) =N(A).
• Property 4 If G is an LR(k) grammar, then there exists LR(K’) such that K’>K
• Property 5 The class of deterministic languages is a proper subclass of the
class of context-free languages.
The class of deterministic languages can be denoted by
• Property 6 LR(k) is closed under complementation but not under union and intersection.
LL(K) Parser LR(K) Parser
First L of LL is for left to right and second L is L of LR is for left to right and R is for rightmost
for leftmost derivation. derivation
It follows the left most derivation. It follows reverse of right most derivation.
Using LL parser parser tree is constructed in Parser tree is constructed in bottom up
top down manner. manner.
In LL parser, non-terminals are expanded. In LR parser, terminals are compressed.
Starts with the start symbol(S). Ends with start symbol(S).
Ends when stack used becomes empty. Starts with an empty stack.
Pre-order traversal of the parse tree. Post-order traversal of the parser tree.
Terminal is read after popping out of stack. Terminal is read before pushing into the stack.
It may use backtracking or dynamic
It uses dynamic programming.
programming.
LL is easier to write. LR is difficult to write.
Example: LL(0), LL(1) Example: LR(0), SLR(1), LALR(1), CLR(1)
A top-down parser is a type of parsing
technique that starts with the root of the
parse tree and tries to construct the parse tree
from the top (the start symbol) to the bottom
(the input string). These parsers begin with
the start symbol and apply grammar
productions to transform it into the input
string. Common types of top-down parsers
include Recursive Descent Parsers and LL(1)
Parsers.
• Let's consider an example of a top-down parser using a simple context-free grammar:
• S→if E then S else S
S→if E then S
S→id
E→id=id
E→id
• In this grammar:
• S represents statements.
• E represents expressions.
• If , then, else, id, and =are terminals.
• Consider the input string: if id = id then if id then id else id.
Bottom-up parsing is a technique used in
compiler construction to build the parse tree
of the input string by reducing it to the start
symbol. The parser starts with the input string
and repeatedly applies reduction (or
reduction) operations and shift operations
until the parse tree is constructed. One
commonly used bottom-up parsing method is
the Shift-Reduce Parsing technique.
Reduce with the grammar:
E→E+E
E→E*E
E → (E)
E → id
Let's parse the input string id + id * id using
bottom-up parsing.
• Let's parse the input string "id + id * id" using
bottom-up parsing.
Bottom-Up Parsing Top-Down Parsing
Order of Parsing: Order of Parsing:
Constructs the parse tree from Constructs the parse tree from root
leaves to root. to leaves.
Direction of Construction: Direction of Construction:
Builds the parse tree in post-order. Builds the parse tree in pre-order.
Parsing Technique: Parsing Technique:
Common techniques include Shift- Common techniques include
Reduce parsing and LR parsing. Recursive Descent parsing and LL
parsing.
Lookahead: Lookahead:
Requires less lookahead, often just one Requires more lookahead, especially
symbol (LR(1)). for LL(k) parsers.
Error Handling: Error Handling:
Can often recover from errors more Might face challenges in error
gracefully recovery, as it needs to follow
specific parsing paths.
PDA Examples
• 244 book