Jaideep M. More

software engineer


Syntax Analysis

Context Free Grammars:

Is a tuple G=(VN,VT,P,S)G = (V_{N}, V_{T}, P, S)

  • VnV_{n}: Set of non terminals
  • VTV_{T}: Set of terminals
  • SS: S∈VNS \in V_{N} Start Symbol
  • PP: P⊆VN×(VN∪VT)∗P \subseteq V_{N} \times (V_{N} \cup V_{T})^* Are set of rules that map non-terminals to a set of terminals and non-terminals

Reduced and Extended CFGs:

A non terminal AA is

  • reachable iff: there exists φ1,φ2\varphi_{1}, \varphi_{2} such that S⟹φ1Aφ2S \Longrightarrow \varphi_{1} A \varphi_{2}
  • productive iff: A⟹w ∣ w∈VT∗A \Longrightarrow w \ |\ w \in V_{T}^*

A grammar is a reduced grammar if it has neither unreachable nor non-productive non-terminals.

A grammar is said to be an extended grammar if we add a non terminal S′S' and add the production S′→SS' \rightarrow S.

Derivations:

Expanding a nonterminal according to the productions defined by the grammar is derivation

φ⟹ψ\varphi \Longrightarrow \psi (φ,ψ∈(VN×VT)∗\varphi, \psi \in (V_{N}\times V_{T})^* and φ\varphi derives ψ\psi) iff there exists φ1,φ2∈(VN×VT)∗\varphi_{1}, \varphi_{2} \in (V_{N} \times V_{T})^* and A∈VNA \in V_{N} such that φ=φ1Aφ2\varphi = \varphi_{1}A \varphi_{2} A→α∈PA \rightarrow \alpha \in P ψ=φ1αφ2\psi = \varphi_{1} \alpha \varphi_{2}

Using this we can write for a Language defined by G

L(G)={w∈VT∗∣S⟹w}L(G) = \{w \in V_{T}^* | S \Longrightarrow w \}

Leftmost and Rightmost derivations:

Given a context free grammar G=(VN,VT,P,S)G = (V_{N}, V_{T}, P, S)

In left most derivation we derive the left most non-terminal φ⟹lmψ\varphi \Longrightarrow_{lm} \psi (φ,ψ∈(VN×VT)∗\varphi, \psi \in (V_{N}\times V_{T})^* and φ\varphi left derives ψ\psi) iff there exists φ1∈VT∗\varphi_{1} \in V_{T}^*; φ2∈(VN×VT)∗\varphi_{2} \in (V_{N} \times V_{T})^*; and A∈VNA \in V_{N} such that φ=φ1Aφ2\varphi = \varphi_{1}A \varphi_{2} A→α∈PA \rightarrow \alpha \in P ψ=φ1αφ2\psi = \varphi_{1} \alpha \varphi_{2}

In right most derivation we derive the right most non-terminal φ⟹rmψ\varphi \Longrightarrow_{rm} \psi (φ,ψ∈(VN×VT)∗\varphi, \psi \in (V_{N}\times V_{T})^* and φ\varphi right derives ψ\psi) iff there exists φ1∈(VN×VT)∗\varphi_{1} \in (V_{N} \times V_{T})^*; φ2∈VT∗\varphi_{2} \in V_{T}^*; ; and A∈VNA \in V_{N} such that φ=φ1Aφ1\varphi = \varphi_{1}A \varphi_{1} A→α∈PA \rightarrow \alpha \in P ψ=φ1αφ2\psi = \varphi_{1} \alpha \varphi_{2}

Ambiguous Grammar:

A grammar that has

  • two left most derivation for the same string
  • two right most derivation for the same string
  • two syntax trees for the same string is called ambiguous.

It is undecidable if the grammar is ambiguous.

Pushdown Automata:

A PDA is defined using a tuple P=(V,Q,Δ,q0,F)P = (V, Q, \Delta, q_{0}, F)

  • VV: Input alphabet
  • QQ: Finite set of states (Stack Symbols)
  • q0q_{0}: Initial State
  • FF: Set of Final states
  • Δ\Delta: Δ⊆(Q+×(V∪ϵ))×Q∗\Delta \subseteq (Q^+ \times (V \cup \epsilon)) \times Q^* (Reads one input alphabet and pops multiple items from the stack, pushes none or multiple items on the stack)

for γ∈Q+\gamma \in Q^+, w∈V∗w \in V^*, (γ,w)(\gamma, w) is a configuration The binary relation step on configuration is defined by: (γ,aw)⊢P(γ′,w)(\gamma, aw) \vdash_{P} (\gamma', w) if there exists γ1\gamma_{1} such that

  • γ=γ1γ2\gamma = \gamma_{1}\gamma_{2}
  • γ′=γ1γ3\gamma' = \gamma_{1}\gamma_{3}
  • (γ2,a,γ3)∈Δ(\gamma_{2}, a, \gamma_{3}) \in \Delta

The language accepted by PDA can be then defined as

L(P)={w∈V∗∣∃qf∈F:(q0,w)⊢M∗(qf,ϵ)}L(P) = \{ w \in V^* | \exists q_{f}\in F: (q_{0}, w) \vdash_{M}^* (q_{f}, \epsilon) \}

Context Free Items and Item pushdown automata:

An item (A,α,β)(A, \alpha, \beta) is denoted as [A→α.β][A \rightarrow \alpha.\beta] [A→α.][A \rightarrow \alpha.] is a complete item

Item Pushdown Automata: Given a CFG G=(VN,VT,P,S)G = (V_{N}, V_{T}, P, S) we create its extended version by adding the nonterminal S′S' and adding a production S′→SS' \rightarrow S

Then the item pushdown automata can be defined as PG=(VT,ITG,δ,[S′→.S],{[S′→S.]})P_{G} = (V_{T}, IT_{G}, \delta, [S' \rightarrow .S], \{[S' \rightarrow S.]\})

TOP DOWN Parser:

Read input from left to right. Construct the syntax tree in a top-down manner sstarting with a node labeled with the start symbol.

Recursive Descent Parsing: Uses Fifo\text{Fifo} sets to make expansion deterministic

Fifo(N→α)=First1(α)⊕1Follow1(N) \text{Fifo}(N \rightarrow \alpha) = \text{First}_1(\alpha) \oplus_1 \text{Follow}_1(N)

⊕k\oplus_{k}: returns the k-length prefix of the concatenation of its operand strings

The Fifo\text{Fifo} set for a particular production contains the set of 1-length prefix of the string that they can generate. This allows us to use make deterministic choice as to which production to use while parsing a given string.

In cases where the given production may also generate an empty-string ϵ\epsilon we also have to consider which character might follow the string that can be generated by the production, and thus Follow1\text{Follow}_{1} is also used.

First1(α)={w:1∣α⟹w,w∈VT∗} \text{First}_1(\alpha) = \{w:1 \mid \alpha \Longrightarrow w, w \in V_{T}^*\} Follow1(N)={a∈VT∣∃α,γ:S⟹αNaγ} \text{Follow}_{1}(N) = \{a \in V_{T} \mid \exists \alpha, \gamma: S \Longrightarrow \alpha N a \gamma\}

LL(k) Grammar:

Given a grammar G=(VN,VT,P,S)G = (V_{N}, V_{T}, P, S) is an LL(k)\text{LL}(k) where kk is a natural number, iff the following holds

S⟹∗uYα⟹uβα⟹∗ux S \Longrightarrow^* uY\alpha \Longrightarrow u\beta \alpha \Longrightarrow^* ux S⟹∗uYα⟹uγα⟹∗uy S \Longrightarrow^* uY\alpha \Longrightarrow u\gamma \alpha \Longrightarrow^* uy

if k:x=k:yk:x = k:y then β=γ\beta = \gamma

In simple terms we dont want two distinct productions for a non-terminal to yield two strings that have a same k-length prefix.

Recursive and LL(K): A non-terminal AA is called left recursive if A⟹+AaA \Longrightarrow^+ Aa A CFG GG is left-recursive if it contains at least one left-recursive non-terminal GG is not LL(k)\text{LL}(k) if it is left-recursive

BOTTOM UP PARSER:

Bottom up parsing by pruning handles:

Handle:

Leftmost set of adjacent leaves forming a complete branch.

Suppose A→α∈P;α∈(VN∪VT)∗A \rightarrow \alpha \in P ; \alpha \in (V_{N} \cup V_{T})^*, then while parsing a string that was generated using the above production, there will come an instance where the AST has the non-terminal AA having children α\alpha. This α\alpha is then an handle.

While parsing we will recursively prune handles. This corresponds to a reverse rightmost derivation.

Now we need a way that by successively reading the input we want to identify the handles, which will allow us to do reduction.

For this we create a characteristic FSM of GG.

Characteristic FSM of GG:

a characteristic FSM of GG is a NFSM ch(G)={Q,V,Δ,q0,F}ch(G) = \{Q, V, \Delta, q_{0}, F\}

  • QQ: Q=ITGQ = \text{IT}_{G} the states of the FSM are the items of the GG
  • VV: V=(VN∪VT)V = (V_{N} \cup V_{T}) the alphabet is the set of non-terminals and terminals
  • q0:q_{0}: is the initial state and q0=[S′→.S]q_{0} = [S' \rightarrow .S]
  • F:F: FF is a set of complete items. Used to identify handles

To draw the ch(G)ch(G):

We will first write the extended version of the grammar. Then we write each production in PP in item format.

Ex: for a production S→aSb∣ϵS \rightarrow aSb \mid \epsilon we will draw the states for this production as

[S→.aSb]→a[S→a.Sb]→S[S→aS.b]→b[S→aSb.] [S \rightarrow .aSb] \rightarrow^a [S \rightarrow a.Sb] \rightarrow^S [S \rightarrow aS.b] \rightarrow^b [S \rightarrow aSb.] [S→.] [S \rightarrow .]

Then we will add epsilon transitions from the item of the form [X→α.Yβ][X \rightarrow \alpha.Y\beta] to all the states of [Y→.γ][Y \rightarrow .\gamma]

We will then make the NFSM into DFSM by using subset construction. This deterministic version is denoted as LR0(G)=(Qd,V,δd,q0,Fd)LR_{0}(G) = (Q_{d}, V, \delta_{d}, q_{0}, F_{d})

When we do subset construction some of the items will be merged into a single state.

Building the LR(0) Pushdown Automaton:

LR0(G)LR_{0}(G) interpreted as a PDA P0(G)=(Γ,VT,Δ,q0,{qf})P_{0}(G) = (\Gamma, V_{T}, \Delta, q_{0}, \{q_{f}\})

  • Γ\Gamma: Stack Alphabet Γ=Qd\Gamma = Q_{d}
  • VTV_{T}: Input Alphabet
  • q0q_{0}: [S′→.S][S' \rightarrow .S] the start state of LR0(G)LR_{0}(G)
  • qfq_{f}: [S’→S.]{[S’ \rightarrow S.]} the final state of LR0(G)LR_{0}(G)
  • Δ\Delta: Δ⊆Γ∗×(VT∪{ϵ})×Γ∗\Delta \subseteq \Gamma^* \times (V_{T} \cup \{\epsilon\}) \times \Gamma^*
shift:

(q,a,qδd(q,a))∈Δ(q, a, q\delta_{d}(q, a)) \in \Delta if δd(q,a)\delta_{d}(q, a) is defined Consume the input aa and push the successor state of qq under aa.

reduce:

(q,q1⋯qn,ϵ,q,δd(q,X))∈Δ(q, q_{1}\cdots q_{n}, \epsilon, q, \delta_{d}(q, X)) \in \Delta, if [X→α.][X \rightarrow \alpha.] at top of the stack. ∣α∣=n|\alpha| = n We pop ∣α∣|\alpha| elements from the stack and push the new stack under XX onto the stack.

Non determinism in P0(G)P_{0}(G):

States with shift-reduce conflict:

Have atleast one read item [X→α.aβ][X \rightarrow \alpha.a\beta] and one complete item [Y→γ.][Y \rightarrow \gamma.]

States with reduce-reduce conflict:

Have atleast two complete items [X→.α],[Y→.β][X \rightarrow .\alpha], [Y \rightarrow .\beta]

A state with conflicts is inadequate.

Adding Lookahead:

a LR0\text{LR}_{0} item is [X→α.β][X \rightarrow \alpha.\beta], a LRk\text{LR}_{k} item is [X→α.β,L][X \rightarrow \alpha.\beta, L], the LL here is the lookahead set.

LR Parser:

Take their decision to shift or reduce by consulting:

  1. Top of the stack
  2. Lookahead

These are used as an input for the Action table and the appropriate action is given by Action[γ,L]\text{Action}[\gamma, L]

A goto table records the transition function of a characteristic automaton δd(G)\delta_{d}(G).