Siksha Sarovar

Siksha Sarovar (sikshasarovar.com) is a free educational web application that helps students in India learn programming and prepare for academic and competitive exams. The platform offers structured coding courses (C, C++, Python, Java, HTML, CSS, PHP, Power BI, AI, Machine Learning, Data Science), complete university curriculum notes for BCA/MCA students with previous year question papers, Class 10 and Class 12 CBSE/HBSE school notes, and dedicated preparation material for SSC, UPSC, Banking, Railway and other government exams. Browsing the site is completely free and requires no account. Users may optionally sign in with Google solely to save their learning progress, quiz scores and personal preferences across devices.

Privacy Policy | Terms of Service | Contact Siksha Sarovar | About Siksha Sarovar

v4.0.9 · PWA
Siksha Sarovar logo
Siksha Sarovar
Your Learning Universe

Siksha Sarovar is a free e-learning platform for coding courses, BCA university notes and competitive exam preparation. Optional Google sign-in saves your learning progress across devices.

Initializing knowledge base…
Compiling modules 0%

Unit 2 — Syntactic Parsing: Top-Down, Bottom-Up & CYK Algorithm

Lesson 16 of 39 in the free Natural Language Processing notes on Siksha Sarovar, written by Rohit Jangra.

Syntactic Parsing Algorithms

Parsing is the process of analyzing a sentence according to a grammar and producing its parse tree(s). Given a CFG (Unit 2, previous lesson), there are several algorithmic strategies to search for a valid parse.

1. Top-Down Parsing

Starts from the start symbol (S) and repeatedly expands non-terminals using grammar rules, trying to match the input sentence left to right.

Start: S
Try:   S -> NP VP
Try:   NP -> 'Riya'  ✓ matches first word
Try:   VP -> V NP
Try:   V -> 'reads'  ✓ matches next word
Try:   NP -> Det N -> ... matches remaining words
  • Pros: Never explores trees inconsistent with the grammar's start symbol.
  • Cons: Can waste time on rules that will never match the actual input (no lookahead at the words); struggles with left-recursive rules (e.g. NP -> NP PP) which can loop forever.

2. Bottom-Up Parsing

Starts from the input words (terminals) and works upward, combining them into larger constituents until the start symbol S is reached.

Input:  Riya   reads   a   book
Step1:  NNP    V       Det  N
Step2:  NP     V       NP        (combine 'Riya'->NP, 'a book'->NP)
Step3:  NP     VP                 (combine V NP -> VP)
Step4:  S                          (combine NP VP -> S)
  • Pros: Always works directly from the actual input words, so it never explores a rule irrelevant to the sentence.
  • Cons: Can build constituents that never end up part of a full valid parse (wasted work); doesn't know the "target" is S until the very end.

Using NLTK's Chart Parser (Top-Down Strategy)

import nltk
from nltk import CFG, ChartParser

grammar = CFG.fromstring("""
S -> NP VP
NP -> 'Riya' | Det N
VP -> V NP
Det -> 'a'
N -> 'book'
V -> 'reads'
""")

parser = ChartParser(grammar)
sentence = ['Riya', 'reads', 'a', 'book']
for tree in parser.parse(sentence):
    print(tree)
    tree.pretty_print()
# (S (NP Riya) (VP (V reads) (NP (Det a) (N book))))

3. The CYK (Cocke-Younger-Kasami) Algorithm

CYK is a dynamic programming bottom-up algorithm that parses in guaranteed O(n³) time — much more efficient than naive backtracking parsers for longer sentences. It requires the grammar to be in Chomsky Normal Form (CNF), where every rule is either A -> B C (two non-terminals) or A -> a (one terminal).

CYK builds a triangular table: cell [i, j] holds the set of non-terminals that can generate the substring from word i to word j.

Sentence: "the dog barked"  (CNF grammar assumed)

        the        dog          barked
the    {Det}     {NP}         {S}         <- combines whole sentence
dog       -      {N}          {VP}? no -> combine dog+barked
barked    -        -          {V}
# CYK core idea in pseudocode
def cyk_parse(words, grammar_cnf):
    n = len(words)
    table = [[set() for _ in range(n)] for _ in range(n)]
    # Fill diagonal: single-word constituents
    for i, w in enumerate(words):
        table[i][i] = grammar_cnf.tags_for_word(w)
    # Fill table for increasing substring lengths
    for length in range(2, n + 1):
        for i in range(n - length + 1):
            j = i + length - 1
            for k in range(i, j):
                for B in table[i][k]:
                    for C in table[k+1][j]:
                        table[i][j] |= grammar_cnf.rules_producing(B, C)
    return 'S' in table[0][n-1]   # sentence is valid if S spans the whole table

Dependency Parsing (Alternative to Constituency Parsing)

Instead of nested phrases (NP, VP), dependency parsing represents a sentence as directed grammatical relations between word pairs (e.g. subject, object).

import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("Riya reads a book")
for token in doc:
    print(f"{token.text:10} --{token.dep_:10}--> {token.head.text}")
# Riya       --nsubj    --> reads
# reads      --ROOT     --> reads
# a          --det      --> book
# book       --dobj     --> reads

Comparing Parsing Strategies

StrategyDirectionTime complexityNotes
Top-downS → wordsExponential (naive)Wastes effort on rules that don't fit; grammar-driven
Bottom-upWords → SExponential (naive)Wastes effort on unused constituents; data-driven
CYKWords → S (DP)O(n³)Requires CNF grammar; guaranteed efficient
Dependency parsingWord-to-word linksFast (often linear, with modern parsers)No phrase-structure tree; used in most production NLP systems today