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 setq
ed 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)
null
.
(random n)
(nth n list)
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 load
ed into clisp and
contains a correct definition of the function speak
.