CFG for the programming language
↓
|--------|
a sequence of tokens → | Parser | → parse tree if the sequence is syntactically valid
|--------|
E : E '+' E | INT
E : E '+' E | INTINT '+' INT E
/|\
E + E
| |
INT INT
E : E '+' E | INTINT '+' INTE → .... → E
/|\
E + E
| |
int int
E : E '+' E | INTINT '+' INTE → E → E → E
/|\ /|\ /|\
E + E E + E E + E
| | |
INT INT INT
E : E '+' E | INTINT '+' INTE → E → E → E
/|\ /|\ /|\
E + E E + E E + E
| | |
INT INT INT
S : begin S L | if E then S else S | print E
L : end | ; S L
E : num = num
val tok = ref (getToken())
fun advance() = tok := getToken()
fun eat(t) = if t = !tok then advance() else error()
fun S() = case !tok (* read the current token *)
of BEGIN => (eat(BEGIN); S(); L())
| IF => (eat(IF); E(); eat(THEN); S(); eat(ELSE); S())
| PRINT => (eat(PRINT); E())
| _ => error() (* _: matches any remaining token *)
and L() = case !tok
of END => eat(END)
| SEMI => (eat(SEMI); S(); L())
| _ => error()
and E() = (eat(NUM); eat(EQ); eat(NUM))
E : E '+' E | INTINT '+' INTfun E() = case !tok
of INT => eat(INT)
| _ => (E(); eat(PLUS); E())
E : E '+' E | INTINT '+' INTfun E() = case !tok
of INT => eat(INT)
| _ => (E(); eat(PLUS); E())
'+' INT is left unparsedE : E '+' E | INTINT '+' INTfun E() = case !tok
of INT => (E(); eat(PLUS); E())
| INT => eat(INT)
E : E '+' E | INT
E : E '+' E | INT
Which new grammar
Which new grammar
E : E '+' E | INT
E : E '+' E | INT
E : INT E'
E' : '+' E E' | ε
E : INT E'
E' : '+' E E' | ε
fun E() = case !tok
of INT => (eat(INT); E'())
and E'() = case !tok
of '+' => (eat('+'); E(); E'())
| EOF => () (* apply the rule E' -> ε *)
| _ => error()
E : T '+' T
T : E | INT
E T '+' T E '+' TE : T '+' T
T : E | INT
A1 ⟼ E
A2 ⟼ T
ɑ ⟼ '+' T
β is absent
ɣ ⟼ ε
δ ⟼ INT
E : T '+' T
T : E | INT
E : T '+' T
T : INT T'
T' : '+' T T' | ε
Takeaway: A grammar that is difficult to parse (e.g. left recursive grammar) can be transformed into an equivalent grammar that is easier to parse.
E: E + E | E * E | INT
INT + INT * INT?E: E + E | E * E | INT
INT + INT * INT? E E
/ | \ / | \
E * E OR E + E
/|\ | | /|\
E + E INT INT E * E
| | | |
INT INT INT INT
E: E + E | E * E | INT
==> ...
(Undesired) (Desired)
E E
/ | \ / | \
E * E E + E
/|\ | | /|\
E + E INT INT E * E
| | | |
INT INT INT INT
(Undesired) (Desired) (Refactored)
E E E
/ | \ / | \ / | \
E * E E + E E + E
/|\ | | /|\ | |
E + E INT INT E * E T T
| | | | | /|\
INT INT INT INT INT T * T
| |
INT INT
E: E + E | E * E | INT
==>
E: E + E | T
T: T * T | INT
(Undesired) (Desired) (Refactored)
E E E
/ | \ / | \ / | \
E * E E + E E + E
/|\ | | /|\ | |
E + E INT INT E * E T T
| | | | | /|\
INT INT INT INT INT T * T
| |
INT INT
E: E + E | T
T: T * T | INT | ( E )
INT + INT + INT?E: E + E | T
T: T * T | INT | ( E )
INT + INT + INT? (Left-associative) (Right-associative)
E E
/ | \ / | \
E + E OR E + E
/ | \ | | / | \
E + E T T E + E
| | | | | |
T T INT INT T T
| | | |
INT INT INT INT
E: E + E | T ==> ...
T: T * T | INT | ( E )
(Left-associative) (Right-associative) (Refactored)
E E
/ | \ / | \
E + E E + E
/ | \ | | / | \
E + E T T E + E
| | | | | |
T T INT INT T T
| | | |
INT INT INT INT
E: E + E | T ==> ...
T: T * T | INT | ( E )
(Left-associative) (Right-associative) (Refactored)
E E E
/ | \ / | \ / | \
E + E E + E E + T
/ | \ | | / | \ / | \ |
E + E T T E + E E + T INT
| | | | | | | |
T T INT INT T T T INT
| | | | |
INT INT INT INT INT
E: E + E | T ==> E: E + T | T
T: T * T | INT | ( E ) T: T * T | INT | ( E )
(Left-associative) (Right-associative) (Refactored)
E E E
/ | \ / | \ / | \
E + E E + E E + T
/ | \ | | / | \ / | \ |
E + E T T E + E E + T INT
| | | | | | | |
T T INT INT T T T INT
| | | | |
INT INT INT INT INT
E: E + T | T
T: T * T | INT | ( E )
INT * INT * INT? (Left-associative) (Right-associative)
E E
| |
T T
/ | \ / | \
T * T T * T
/ | \ | | / | \
T * T INT INT T * T
| | | |
INT INT INT INT
E: E + T | T ==> E: E + T | T
T: T * T | INT | ( E ) T: T * F | F
F: INT | ( E )
INT * INT * INT? (Left-associative) (Right-associative) (Refactored)
E E E
| | |
T T T
/ | \ / | \ / | \
T * T T * T T * F
/ | \ | | / | \ / | \ |
T * T INT INT T * T T * F INT
| | | | | |
INT INT INT INT F INT
|
INT
E: E + T | T ==> E: E + T | T ==> E : T E'
T: T * T | INT | ( E ) T: T * F | F E': + T E' | ε
F: INT | ( E ) T : F T'
T': * F T' | ε
F: INT | ( E )
E: T E'
E': + T E' | ε
T: F T'
T': * F T' | ε
F: INT | ( E )
fun E() =
(T(); Eprime())
and Eprime() =
case !tok
of PLUS => (eat(PLUS); T(); Eprime())
| _ => () (* epsilon *)
and T() =
(F(); Tprime())
and Tprime() =
case !tok
of TIMES => (eat(TIMES); F(); Tprime())
| _ => () (* epsilon *)
and F() =
case !tok
of INT => eat(INT)
| LPAREN => (eat(LPAREN); E(); eat(RPAREN))
| _ => error()
S: if E then S else S
| if E then S
S: if E then S else S
| if E then S
fun S() =
case !tok
of IF => ...
S: if E then S else S ==> ...
| if E then S
S: if E then S else S ==> S: if E then S S'
| if E then S S': else S | ε
fun S() =
case !tok
of IF => (eat(IF); E(); S(); Sprime())
| _ => error()
and Sprime() =
case !tok
of ELSE => (eat(ELSE); S())
| _ => () (* epsilon *)
E: E + T | T | T + INT == elimination => E: T E' | T + INT E'
T: T * T | INT | ( E ) E': + T E' | ε
T: INT T' | ( E ) T'
T': * T T' | ε
E: E + T | T | T + INT == elimination => E: T E' | T + INT E' == left factoring => E: T X
T: T * T | INT | ( E ) E': + T E' | ε X: E' | + INT E'
T: INT T' | ( E ) T' E': + T E' | ε
T': * T T' | ε T: INT T' | ( E ) T'
T': * T T' | ε
fun E() = (T(); X())
and X() = case !tok
of PLUS => (eat(PLUS); eat(INT); Eprime())
| _ => (Eprime())
and Eprime() =
case !tok
of PLUS => (eat(PLUS); T(); Eprime())
| _ => () (* epsilon *)
and T() =
case !tok
of INT => (eat(INT); Tprime())
| LPAREN => (eat(LPAREN); E(); eat(RPAREN); Tprime())
| _ => error()
and Tprime() =
case !tok
of TIMES => (eat(TIMES); T(); Tprime())
| _ => () (* epsilon *)
INT + ( INT )E: E + T | T | T + INT == elimination => E: T E' | T + INT E' == left factoring => E: T X
T: T * T | INT | ( E ) E': + T E' | ε X: E' | + INT E'
T: INT T' | ( E ) T' E': + T E' | ε
T': * T T' | ε T: INT T' | ( E ) T'
T': * T T' | ε
fun E() = (T(); X())
and X() = case !tok
of PLUS => (eat(PLUS); eat(INT); Eprime())
| _ => (Eprime())
and Eprime() =
case !tok
of PLUS => (eat(PLUS); T(); Eprime())
| _ => () (* epsilon *)
and T() =
case !tok
of INT => (eat(INT); Tprime())
| LPAREN => (eat(LPAREN); E(); eat(RPAREN); Tprime())
| _ => error()
and Tprime() =
case !tok
of TIMES => (eat(TIMES); T(); Tprime())
| _ => () (* epsilon *)
INT + ( INT )E: E + T | T | T + INT == elimination => E: T E' | T + INT E' == left factoring => E: T X
T: T * T | INT | ( E ) E': + T E' | ε X: E' | + INT E'
T: INT T' | ( E ) T' E': + T E' | ε
T': * T T' | ε T: INT T' | ( E ) T'
T': * T T' | ε
E => T X => T E' => INT T' E' => INT E' => INT + T E'
=> INT + ( E ) T' E' => INT + ( T X ) T' E'
=> INT + ( INT T' ) T' E' => INT + ( INT ) T' E'
=> INT + ( INT ) E' => INT + ( INT )
INT + ( INT )E: E + T | T | T + INT == elimination => E: T E' | T + INT E' == left factoring => E: T X
T: T * T | INT | ( E ) E': + T E' | ε X: E' | + INT E'
T: INT T' | ( E ) T' E': + T E' | ε
T': * T T' | ε T: INT T' | ( E ) T'
T': * T T' | ε
E => T X => T E' => INT T' E' => INT E' => INT + T E' => INT + ( E ) T' E'
=> INT + ( T X ) T' E' => INT + ( INT T' ) T' E' => INT + ( INT ) T' E' => INT + ( INT ) E' => INT + ( INT )
fun E() = (T(); X())
and X() = case !tok
of PLUS => (eat(PLUS); eat(INT); Eprime())
| _ => (Eprime())
and Eprime() =
case !tok
of PLUS => (eat(PLUS); T(); Eprime())
| _ => () (* epsilon *)
and T() =
case !tok
of INT => (eat(INT); Tprime())
| LPAREN => (eat(LPAREN); E(); eat(RPAREN); Tprime())
| _ => error()
and Tprime() =
case !tok
of TIMES => (eat(TIMES); T(); Tprime())
| _ => () (* epsilon *)