CS30 - Spring 2016 - Class 14

Example code in this lecture

   cfg.py

Lecture notes

  • the cfg.py code shows one way of implementing the CFG we saw in the slides
       - terminals are represented as strings   

       - each nonterminal is represented as a function, e.g. noun, verb, verb_phrase, etc.
          - they return one of two things, representing the right hand side of the rule:
             - a string
             - a list of functions (could also be a list of functions and strings, though we don't utilize that option)
          - if there are multiple options (i.e through |) then a random choice is made

       - noun, verb, article, adjective and adverb all generate only terminals
          - they randomly select between possible words (strings) using random.choice
          - they each return a string

       - pre_noun_phrase, noun_phrase, verb_phrase and sentence all generate more nonterminals (though they don't necessarily have to)
          - they each return a list of functions, representing a rule that generates a nonterminal on the right hand side

  • the process function in cfg.py code takes in a cfg rule (either a string or a list of functions) and randomly generates a string in that language
       - the function is recursive!
          - this is not too surprising since CFG have a recursive feeling to them
       
       - the base case is if we're dealing with a terminal (i.e a string)
       - the recursive case is if we have a list of nonterminals (i.e. functions)
          - for each item (function) in this list:
             - call the function "item()"
             - and then call process on whatever it give in return
                - this will either be a string (in the case of a rule that generates a terminal)
                - or another list of functions
             - the results are then appended together into one string

       - we can call the process function by getting it started with [sentence], i.e.
          >>> process([sentence])
          'the bagel eats intentionally'

          - for this to happen, the recursion would be something like:
             - top call: process([sentence])
             - this would then make two recursive calls to return: process(noun_phrase()) + " " + process(verb_phrase())
                - the call to noun_phrase returns [article, pre_noun_phrase]
                   - which then is passed to process
                   - article gives us 'the'
                   - and the pre_noun_phrase pics just [noun]
                      - the noun "bagel" is chosen
                - ...

  • printing out lots of random derivations from the grammar
       - if we put this call in a loop, we can get lots of random strings:

          >>> for i in range(10):
          ...    print process([sentence])

          a milk eats
          a bagel sleeps
          a idea sleeps furiously
          a green idea eats soothingly
          a green cow sleeps intentionally
          the colorless smelly cow sleeps
          the colorless cow swims soothingly
          the bagel swims intentionally
          a idea sprints
          the colorless colorless colorless green cow swims intentionally