X→Y
abXcd → abY Zcd
S → string0 → string1 → ...stringn S →∗ stringn
L(ϵT ) := {t1 . . . tn | ∀i ti ∈ T ∧ S →∗ → t1 . . . tn }
non-terminals: uppercase, terminals: lowercase
S → [S]
S→ϵ
Scanner / lexer → Parser → reject/accept CFG
S → aSa | T
T → bT b | ϵ
1
Derivation Algorithm
1. Begin with a string only starting with S
2. Replace X string with any production on the RHS, Y1 , . . . , Yn
2
Example
S →E+S |E
E → number | S
Derive (1 + (2 + (3 + 4))) + 5. Leftmost/rightmost derive.
3
Parse Tree
Derivation is a sequence of productions. You can add RHS productions as the
children nodes to the PT.
Input string can be constructed from DFS in-order traversal of PT
PT shows the association of operations, input string doesn’t
E.g. nodes lower in the PT are more deeply nested than those that are
higher and take higher precedence
1
4
Example
E → E ∗ E | E + E | (E) | id
Parse tree is “concrete syntax”, AST is a much more compact format.
5
Recap
p ∈ L(G) is the program that follows the language of the CFG.
Need to build PT to understand structure.
6
Ambiguity
Different PT from same grammar G from unorderd productions.
E → E + E′ | E′
E ′ → id ∗ E | id | (E) ∗ E ′ | (E)
Stratifies grammar enforced precendence of * over +. In the parse tree, *
are nested more deeply than +
In other words, * binds more tightly than +.
Or, you can have an ambiguous grammar with precedence and associative
rules. That way, parse trees can be wrong or right.
if E1 then if E2 then S1 else S2
You can either interpret the else statement belongs to either if statement, so
you get 2 different PTs, using the production rule.
2