Q3Compiler Design
Question
Explain the concept of FIRST and FOLLOW sets with an example.
Answer
FIRST and FOLLOW sets are mathematically calculated terminal collections that dictate exactly how predictive Top-Down Parsers (like LL(1)) choose production rules without backtracking.
In the realm of compiler design, specifically for Top-Down Predictive Parsers (like the LL(1) parser), the parser must decide exactly which grammatical production rule to execute just by looking at the current input token. To achieve this deterministic, non-backtracking behavior, the compiler engineers mathematically compute two critical sets for the Context-Free Grammar: the FIRST set and the FOLLOW set.
Defining the FIRST Set
The FIRST(X) set is mathematically defined as the absolute collection of all terminal symbols that can begin any string derived from the symbol X. If X can derive the empty string , then is violently injected into FIRST(X). It tells the parser: "If I am trying to build X, what are the possible first tokens I should expect to see?"
Defining the FOLLOW Set
The FOLLOW(A) set is strictly defined for non-terminals. It is the collection of all terminal symbols that can physically appear immediately to the right of A in any valid derivation. Crucially, the symbol is absolutely never allowed in a FOLLOW set. If A is the rightmost symbol in a derivation, the end-of-input marker $ is injected.
A Rigorous Example
Consider the following Context-Free Grammar: 1. 2. 3.
- Calculating FIRST sets:
-
FIRST(A): The rules are and . Therefore,FIRST(A) = {a, epsilon}. -FIRST(B): The rules are and . Therefore,FIRST(B) = {b, c}. -FIRST(S): starts with . So we includeFIRST(A)(which isa). But because can become , can also start with . So we must also includeFIRST(B). Therefore,FIRST(S) = {a, b, c}. - Calculating FOLLOW sets:
-
FOLLOW(S): Because is the start symbol, we immediately inject the end marker$.FOLLOW(S) = {$}. -FOLLOW(A): Look at . What directly follows ? It is . Therefore,FOLLOW(A)mathematically inheritsFIRST(B).FOLLOW(A) = {b, c}. -FOLLOW(B): Look at . is at the absolute end of the string, meaning whatever follows must follow . Therefore,FOLLOW(B) = FOLLOW(S) = {$}.
By computing these sets, the parser can perfectly populate its predictive parsing table, completely eliminating catastrophic trial-and-error backtracking.