MC logo

CS 231 Assignment 4


CS 231 Programming Assignments

CSC 231

Assignment 4
Due: November 29, Midnight
50 Pts.

For this assignment, you will use lisp to generate random strings from a context-free grammar. The grammar will be represented in an alist bound to the name curr-grammar. For instance,

(setq curr-grammar '(
	(Expr . (
		(Expr + Prod)
		(Prod)  )
	)
	(Prod . (
		(Prod * Term)
		(Term)  )
	)
	(Term . ((id) ( "(" Expr ")" )))
	(id . ((a) (b) (c)))
))

corresponds to the grammar

<expr> --> <expr> + <prod> | <prod>
<prod> --> <prod> * <term> | <term>
<term> --> <id> | ( <expr> )
<id> --> a | b | c

In curr-grammar, each dot pair represents one replacement. The left item of each pair is a nonterminal symbol, and the right side is a list of replacements. Each member of the list represents one alternative which may replace the right side. Each alternative is itself a list of the items of the replacement. Each replacement is a list, even if if it contains only a single item.

You are to write a lisp function (speak) which generates a sentence from the grammar at random. It should assume that curr-grammar has been setqed to the CFG upon which it should operate. For instance, using the above grammar, we could produce something like this:

[1]> (load "grammar.lisp")
;; Loading file grammar.lisp ...
;; Loading of file grammar.lisp is finished.
T
[2]> (load "rsent.lisp")
;; Loading file rsent.lisp ...
;; Loading of file rsent.lisp is finished.
T
[3]> (speak)
(C + "(" A * "(" A + "(" "(" A * C + "(" B + C + "(" C * "(" B * B + A ")" * C
 + B ")" + "(" "(" B + B * "(" A ")" * B * B ")" + B ")" * "(" B * A ")" * C *
 A * A * A * "(" "(" "(" B + C * B * A * B * B + C ")" ")" * C + B + "(" "(" C
 * "(" "(" A ")" * B * C + C ")" * "(" "(" C * B * A * A ")" ")" * "(" C ")" *
 C + "(" "(" C ")" + B + "(" B * C * A ")" * A * "(" A ")" * C * C + A + C ")"
 * C * C * A * C ")" * B + C + C * A * "(" "(" C * C ")" * B * B ")" * C + C *
 B * B * A * A * C * A + C * B * "(" A + C + A + A ")" ")" * C + "(" C * C + B
 + C ")" * "(" B * B + C + B + A * B * "(" B + B * C ")" ")" + "(" A + C * B
 ")" ")" * A + A * B * A ")" + B ")" * B ")" * "(" "(" "(" A ")" ")" + B * C *
 C ")" ")" + "(" A * "(" C * B + A * B * A ")" * B * A + "(" A ")" * A * C * B
 * A + A ")" + A * "(" B ")" * B * A ")" + A + C
)
[4]> (speak)
("(" "(" "(" A * B * A * A + "(" C * A + B * B + B ")" + B * A * C * C * A ")"
 * "(" B + "(" B * A * C ")" * C + A + C * C * B * "(" B * A * C * A * A ")"
 ")" + C + A * A * B + C ")" ")" * A
)
[5]> (speak)
(B)
[6]> (speak)
(A)
[7]> (speak)
(A * B)
[8]> (speak)
(B)
[9]> (speak)
(B + A * B + C * "(" A * C ")")
[10]> (speak)
(B * C + A * B)
[11]> (speak)
(B * "(" C + C * "(" A * B * B + B * "(" A * C + B * "(" B ")" ")" * B * B + B
 + A + B + A * A + A + B * "(" "(" C ")" + C * C * B ")" * A + A + "(" B ")" *
 A * C * A * B * "(" B ")" * B ")" ")" * "(" C * B ")"
)

Your (speak) function should start with the list consisting of the start symbol for the grammar. The start symbol is the left side of the first rule (Expr in the current example). Your function should then repeatedly replace each non-terminal symbol in the list with a randomly-selected replacement. It repeats this process until the list contains only terminal symbols.

Bits and Pieces

Here are some useful bits of Lisp you may want to use.

(assoc x alist)
Search the alist for the first member starting with x. If there is none, return null.
(random n)
Generate a random number from 0 up to, excluding n.
(nth n list)
Return the nth member of the list, numbering from zero.

By default, the random function will return the same sequence of random numbers each time you run the program. This is very useful for testing. To get different sequences of random numbers, run:

	(setq *random-state* (make-random-state t))

Too Much

If you're unlucky, the program can keep making the wrong choices, and never reach a sentence (terminal symbols). The essentially puts the program into an infinite loop. To fix this, the grammar which generated the above example actually contained the line

	(Term . ((id) (id) (id) (id) ( "(" Expr ")" )))

Since alternatives are chosen with equal probability, this line makes it much more likely that a Term will be replaced with id rather than (Expr). That reduces the change that the program will increase the length of the sentence generated.

Submission

Submit your program using the form here. Submit a file which can be loaded into clisp and contains a correct definition of the function speak.