Professional Documents
Culture Documents
The input grammar must consist of a list of lists, one per non-terminal in the grammar. The first
element of each sub-list should be the non-terminal; the remaining elements should be the
right-hand sides of the productions for which that non-terminal is the left-hand side. The sublist for the start symbol must come first. Every grammar symbol must be represented as a
quoted string. As an example, here is our familiar LL(1) calculator grammar in the required
format:
(define calc-gram
'(("P" ("SL" "$$"))
("SL" ("S" "SL") ())
("S" ("id" ":=" "E") ("read" "id") ("write" "E"))
("E" ("T" "TT"))
("T" ("F" "FT"))
("TT" ("ao" "T" "TT") ())
("FT" ("mo" "F" "FT") ())
("ao" ("+") ("-"))
("mo" ("*") ("/"))
("F" ("id") ("num") ("(" "E" ")"))
))
The parse table, as returned by function parse-table, must have the same format, except that
every right-hand side is replaced by a pair (a 2-element list) whose first element is the predict
set for the corresponding production, and whose second element is the right-hand side. If you
type
(parse-table calc-gram)
A parse function is provided that accepts a grammar and an input string as arguments. It calls
the parse-table function and then uses it to parse the input, printing a trace of its actions as
it does so, in a manner reminiscent of the Dparse output from the PL/0 compiler. You can
use this function to test your code.
This tells us that SL appears on the right-hand of two productions in the grammar: one with P on
the left-hand side and one with SL on the left-hand side. In the former, the portion of the righthand side after the SL is $$. In the latter, the portion of the right-hand side after the SL is empty
(that is, SL is the last thing on the right-hand side). In a similar vein, if you type
(right-context "mo" calc-gram)
This tells us there is only one production with a mo on the right-hand side. It has FT on the lefthand side, and F FT after the mo on the right-hand side.
The right-context information is useful for constructing FOLLOW sets.
Assuming you use the suggested strategy, you will need to compute the knowledge structure
recursively. This structure consists of a list of 4-element sub-lists, one per non-terminal. Each
sub-list contains (1) the non-terminal itself (call it A), (2) a Boolean indicating whether we
currently think that A * , (3) our current estimate of FIRST(A) {}, and (4) our current
estimate of FOLLOW(A) {}. It is much easier in to keep track of separately, rather than to
include it in the FIRST and FOLLOW sets.
The function to generate the knowledge structure is
(define get-knowledge
Page 2 of 4
If you type
(get-knowledge calc-gram)
This tells us, for example, that FT generates epsilon, but F does not, and
that FOLLOW(mo) = {(, id, num}.
As the base of its recursion, get-knowledge uses an initial, empty structure generated by
function initial-knowledge, which is provided. At each step of the recursion the function makes
use of utility routines that extract information from the current structure:
(define generates-epsilon?
(lambda (w knowledge grammar)
;;; your code here; my version is 7 lines long
))
(define first
(lambda (w knowledge grammar)
;;; your code here; my version is 10 lines long
))
(define follow
(lambda (A knowledge)
(cadddr (symbol-knowledge A knowledge))))
; This is simpler than the other two functions, because it only needs
; to work for individual non-terminals, not for lists of symbols.
If you work in pairs on this assignment, one possible division of labor is for one partner to
write generates-epsilon?, first, and parse-table, while the other partner writes getknowledge. A better strategy, however, may be to start by having one partner write generatesepsilon? while the other writes first. Then sit down together and write getknowledge and parse-table. This is one of those assignments where two heads may work better
than one.
Important: you are required to use only the functional features of Scheme; functions with an
exclamation point in their names (e.g. set!) and input/output mechanisms other than load and
the regular read-eval-print loop are not allowed. (You may find imperative features useful for
debugging. Thats ok, but get them out of your code before you hand anything in.)
Page 3 of 4
Quiz 2
Before the beginning of the next class, finish the quiz 2 on Moodle by answering the
following questions:
1. What does the following code do? Explain your answer.
(apply * (map + '(1 2 3) '(4 5 6) '(7 8 9)))
2. The sort routine in the skeleton file implements a simple version of the classic
quicksort algorithm. Which element does this version use as a pivot (the value
around which to partition the list)?
3. When you open a program in DrScheme/Racket, what color does it use to
display quoted character strings?
Page 4 of 4