CSCI Principles of Programming Languages

Document Sample
CSCI Principles of Programming Languages Powered By Docstoc
					                             Winter 2011 (Jan5-Apr8)
                             Faculty of Computer Science

CSCI 3136 — Principles of Programming Languages

Assignment 3

      Due: Monday, Feb 28, 2011 (written in class, programming by midnight)
Instructor: Karen JIN, CS Bldg 209, 494-8040,
       TA: Kamrooz Naini,
Assignment Instructions:
   The written parts of the assignments have to be handed to the instructor, in class by
the due date.
    The programming part of the assignment have to be submitted using the command
‘submit’ on the computer bluenose. Submit only the source code, i.e., don’t submit exe-
cutables or other binary code. The programming part have to be submitted by midnight
on the due date. Correctness of the programs, efficiency, as well as the programming style
(clarity, comments, use of white space) will me marked.

1) (written, worth 10%)
   Consider the following grammar over the alphabet Σ = {c, d, e}:
               S −→ A B A
               A −→ B c | d A | ϵ
               B −→ e A
   (a) Calculate the First and Follow sets for the non-terminals in this grammar:
   (b) Calculate the Predict set for all non-terminals and fill in the predictive parsing table.
   (c) Is this grammar LL(1)? Explain why or why not.

2) (written, worth 30%)
   Let us follow up on question 6 of assignment 2, i.e., the “Tiger Basic” (TB) language. A
sample program in TB was (with one small modification):

      INPUT X;
      INPUT Y;
30:   IF X >= Y THEN 70;

     T = X;
     X = Y;
     Y = T;
70: IF X == Y THEN finish;
     X = X - Y;
     GOTO 30;
     PRINT X;

   Write a context-free grammar for this language. The non-terminals should be delimited
using angle brackets ⟨ and ⟩. The start symbols should be ⟨program⟩. Use the classical CFG
notation, used in class (for example, not extended BNF notation). The set of terminals
should include:

   • the end-of-input token: eof

   • the semi-colon separator: SEP, the colon: COL

   • identifier: id, number: NUMBER

   • operator of the first (lowest) precedence: OP1, which is the assignment operator =,

   • operators of the second precedence: OP2, which are the comparison operators: <, >,
     <=, >=, ==, and !=).

   • operators of the third precedence: OP3, which are + and -,

   • operators of the fourth precedence: OP4, which are * and /,

   • operators of the fifth (highest) precedence: OP5, which are unary + and -

   • the left and right parentheses: ( and )

   • reserved words: INPUT, IF, THEN, GOTO, PRINT, and END.

    You can write one or several context-free grammars (CFG) for the following questions.
In any case, you need to explain why your grammar satisfies the required conditions.
a) Write a CFG that is sufficient for parsing the sample program. Demonstrate that this is
true by drawing the parse tree of the sample program. Since the tree may be large, you can
present it in pieces and do not have to repeat nearly identical parts. For this part, you do
not have to use all terminals listed above.
b) Write a CFG that satisfies the following conditions, or explain that the grammar you
wrote for a) satisfies these conditions: The grammar is unambiguous. The grammar handles

general expressions with parentheses and all operators mentioned above with correspond-
ing precedence. A general expression can appear between IF and THEN keywords, and the
assignment statement should be just a general expression.
    To demonstrate that the grammar is unambiguous, you could explain how a parser could
derive a left-most (or right-most) derivation in a deterministic way with a look-ahead, if one
c) Write a CFG that satisfies the following conditions, or explain that the grammar you
already wrote for parts a) or b) satisfies these conditions: All operators are associative, except
for comparison operators (OP2). For example, 1+2+3 is a valid expression, but 1==2!=3 is
not; and (1==2)!=3 is again a valid expression.

3) (programming, worth 25%)
    b) Implement a Scheme program median, which ask for a given list of numbers and then
displays their median. This means that if there is an odd number of numbers, they need to
be sorted and the middle one returned; otherwise, if there is an even number of numbers,
the average of the two middle ones must be returned. For example:(median 2 1 3) should
return 2, and (median 11 5 5 2 3) should return 2.5. Here is a sample run:

> (median-interactive)
 Enter input: 1 1 5 5 2 3
 The median is 2.5

    Note: You must not use iterative loops in your program. Use recursions only. You can
use library functions in your implementation; you may also assume that the input has only
single digit numbers.
    You can use the get-line function available in the newer Scheme specification R6RS to
process keyboard input. Here is an example of getting a line of input from the keyboard and
display all the (non-space) elements as a list. (Run the program in DrRacket with language
set as ”Use the language declared in the source”).

 (import (rnrs))

 (define (median-interactive)
  (display "Enter input:")
  (let ((input (get-line(current-input-port))))
     (display (remove #\ (string->list input)))))

   Submit the program in the file named median.scm if you use mzscheme on bluenose, or
the file named median.rkt if you use DrRacket. It is recommended to write your program
with DrRacket.

4) (programming, worth 35%) Submit the functions in the files 4a.scm, 4b.scm, 4c.scm,
and 4d.scm, corresponding to appropriate parts of the assignment if you use mzscheme on
bluenose. If you use DrRacket, name the files with .rkt extension.
    a) Implement a Scheme function has-list?, which tests whether a list contains other
list as an element. For example (has-list? ’(1 2 3)) should return false, and
(has-list? ’(1 2 (3 4) 5)) should return true.
    b) Implement a Scheme function flatten-first, which takes a list as an argument, and
if the list does not contain any other lists as elements, then returns the same list. Otherwise,
if the list contains other lists as elements it “flattens” the first of them, i.e., replaces the
first list as a list of its members. For example, (flatten-first ’(1 2 (3 4) (5 6)))
should return (1 2 3 4 (5 6)), and (flatten-first ’(1 2 () (5 6))) should return
(1 2 (5 6)).
   c) Implement a Scheme function flatten-first-cdr, which is similar to the function
flatten-first in b), except that if the list contains a list L, and it is non-empty, it removes
the first element of L before flattening it. For example,
(flatten-first-cdr ’(1 2 (3 4) (5 6))) should return (1 2 4 (5 6)),
(flatten-first-cdr ’(1 2 (4) (5 6))) should return (1 2 (5 6)), and
(flatten-first-cdr ’(1 2 () (5 6))) should return (1 2 (5 6)).
    d) A parse tree can be represented is so-called bracketed representation, which can be
defined in the following way: If a tree is a terminal, i.e., a leaf, then it is represented by itself.
If a tree has a root A with sub-trees t1 , t2 , . . . tn , then it is represented as (A t1 t2 . . . tn ),
with the exception that a root A with an epsilon-child, corresponding to an epsilon rule, is
represented as (A).
   For example, the bracketed representation of the parse three of the string 001111 in the
grammar defined by the following rules: S → A B, A → 0 A 0, A → ϵ, B → 1 B 1, and
B → ϵ, where S is the start symbol, {S, A, B} are non-terminals, and {0, 1} are terminals is

(S (A 0 (A) 0)
   (B 1
      (B 1 (B) 1)

     The yield of a parse tree represented in this way can be obtained by starting with a
list containing the parse tree as one element, and repeatedly calling flatten-first-cdr on
it, until a list with no elements which are lists is obtained. Implement a Scheme function
my-yield which produces yield of a parse tree as a list of terminals. For example,

(my-yield ’((S (A 0 (A) 0)            (B 1 (B 1 (B) 1) 1 ))))

should produce (0 0 1 1 1 1)


Shared By: