CS 3723/3731 Programming Languages
Final Exam, Spring 2003
Selected Answers (in boldface)

  1. Formal Grammars and Languages:

    1. Consider the following grammar for very simple arithmetic expressions. Here "P" is the start symbol, and "digit" is any one of the ten digits.
             P  --->  E  '#'
             E  --->  E  '+'  T   |   T 
             T  --->  T  '*'  F   |   F 
             F  --->  '('  E  ')'  |  digit
            

      Give the parse tree for the sentence:

        7 * ( 3 + 2 ) #

                              P
                              |
              +---------------+-------------------------+
              |                                         |
              E                                         |
              |                                         |
              T                                         |
              |                                         |
       +------+--------------------+                    |
       |      |                    |                    |
       |      |                    F                    |
       |      |                    |                    |
       |      |      +-------------+-------------+      |
       |      |      |             |             |      |
       |      |      |             E             |      |
       |      |      |             |             |      |
       |      |      |      + -----+------+      |      |
       |      |      |      |      |      |      |      |
       |      |      |      E      |      |      |      |
       |      |      |      |      |      |      |      |
       T      |      |      T      |      T      |      |
       |      |      |      |      |      |      |      |
       F      |      |      F      |      F      |      |
       |      |      |      |      |      |      |      |
       7      *      (      3      +      2      )      #
       
    2. Is the grammar above ambiguous? (Yes or No.) Yes

    3. What is the associativity and precedence of the operators + and *?
      Both associate left-to-right. * has precedence over +.

    4. Which of the two parsing methods that we studied in recitations can utilize this grammar? (Perhaps both, perhaps one, perhaps none. If one or more, you must identify it/them by name.)
      This grammar is suitable for most shift-reduce parsers, but not for recursive descent parsers. (That's why the next questions uses a different equivalent grammar.)

  2. Semantic Actions:

      Consider the following grammar:
           P  --->  E '#'
           E  --->  T { '+'  T }
           T  --->  F { '*'  F }
           F  --->  '('  E  ')'  |  digit
      
    1. Does this grammar have the same language as the previous grammar? (Yes or No.) Yes Does this grammar have the same parse trees as the previous grammar? (Yes or No.) No

    2. Modify and add to the code above so that it will work as an evaluator of integer expressions. (In a recitation, we studied an evaluator using doubles, but this evaluator is to use ints. You can write on the exam, or copy material onto a separate sheet. This code is C, but the parts needing changes are essentially the same as Java, so just don't worry about it.) If the executable is named evala then the following shows what results of runs should be:

        pandora% evala
        (4 + 5)#
        Value: 9
        pandora% evala
        1+3+5+7+9#
        Value: 25
        pandora% evala
        2*2 + 3*3 + 5*5 + 7*7 + (2+9)*(3+8) + 
           (6+7)*(5+8) + (5+6+6)*(4+5+8)#
        Value: 666
        
      Here is an answer, with changes and additions in bold:
      
      #include 
      #include 
      #include 
      char next;
      int E(void);
      int T(void);
      int S(void);
      int F(void);
      void error(int);
      void scan(void);
      
      void main(void) {
         int res;
         scan();
         res = E();
         if (next != '#') error(1);
         else printf("Value: %i\n", res);
      }
      
      int E(void) {
         int res;
         res = T();
         while (next == '+') {
            scan();
            res += T();
         }
         return res;
      }
      
      int T(void) {
         int res;
         res = F();
         while (next == '*') {
            scan();
            res *= F();
         }
         return res;
      }
      
            
      
      int F(void) {
         int res;
         if (isdigit(next)) {
            res = next - '0';
            scan();
         }
         else if (next == '(') {
            scan();
            res = E();
            if (next == ')') scan();
            else error(2);
         }
         else {
            error(3);
         }
         return res;
      }
      
      void scan(void) {
         while (isspace(next = getchar()))
            ;
      }
      
      void error(int n) {
         printf("\n*** ERROR: %i\n", n);
         exit(1);
      }
      

  3. The Lisp Language:

    1. Results of legal inputs:
        
        > 17
        17
        > (+ (* 2 3) (* 8 4))
        38
        > (car '((a b c) d (e)))
        (A B C)
        > (cdr '((a b c) d (e)))
        (D (E))
        > (car (cdr '(a b c)))
        B
        > (cons '(a) '(b c))
        ((A) B C)
        > (append '(a) '(b c))
        (A B C)
        > (list '(a) '(b c))
        ((A) (B C))
        > (cond ((= 4 (* 2 2)) 47)
               (t 54))
        47
        > ()
        NIL
        

    2. Results of erroneous inputs:
        
        > (car (cdr '(a b c))   ;;; missing final )
             )
        B
        > (car (car '(a b c)))  ;;; can't car of an atom
        
        >>Error: The value of X, A, should be a LIST
        
        > (car (cdr (a b c)))  ;;; Lisp will try to evaluate (a b c)
        
        >>Error: The function A is undefined
        
    3. Write a recursive Lisp function dropatoms that will take a list as input and will delete all the atoms at the top level, keeping all lists at the top level.
      Here is one solution:
        
        > (defun dropatoms (x)
             (cond ((null x) nil)
                   ((atom (car x)) (dropatoms (cdr x)))
                   (t (cons (car x) (dropatoms (cdr x)))) ))
        DROPATOMS
        > (dropatoms '((a) b c))
        ((A))
        > (dropatoms '(a b c))
        NIL
        > (dropatoms '(a (b) c))
        ((B))
        > (dropatoms '(a b (c)))
        ((C))
        > (dropatoms '(4 a c (a b) d e (g h)))
        ((A B) (G H))
        > (dropatoms '(6 (a (b) c) (((b))) a b))
        ((A (B) C) (((B))))
                 

  4. The Postscript Language:

    Consider the following Postscript programs:

    1. The two Postscript programs above produce the same output. Use a sketch to show exactly what will be printed.
      Starting at the lower left corner, a large UTSA. Result looks like: .ps, .pdf.

    2. Insert statements at the % above to change the coordinate system so that the output will be at the approximate middle of the page, and will appear vertically (bottom of letters at the right and top of the letters at the left). [Hint: In Postscript, a positive angle goes counter-clockwise.]
      Just add the following at the comment, with result .ps, .pdf:
      
      5 inch 3 inch translate
      90 rotate
      

    3. Change the utsa function so that the parameters to moveto are passed on the stack. Use this to print the UTSA horizontally (not rotated as in 2), so that the bottom of the UTSA is 350 points from the bottom of the page, and so that the UTSA is exactly centered horizontally on the page. [Hint: Use the Postscript function stringwidth which pushes on the stack the width and height moved while printing the string. You will want to just pop the height, which is zero here anyway.]

      Result looks like: .ps, .pdf, with possible code as follows:

      /Times-Bold findfont 144 scalefont setfont
      /utsa { % stack:  x  y
         moveto
         (UTSA) show
      } def
      
      612 2 div
      (UTSA) stringwidth pop 2 div sub % x coordinate
      350 % y coordinate
      utsa
      
      showpage
        
    4. Write Postscript code that will fill the page with a 0.5 graylevel by tracing a path around the border of the page and then filling it.
      The answer is a function in the result below.

    5. Add to the part 4 code and use the method in part 3 to place a white UTSA with a black outlined border centered exactly horizontally on the page (keeping the gray background). [Hint: (UTSA) false charpath creates a path outlining the characters. Also 0 is the code for black.]
      Result looks like: .ps, .pdf, with possible code as follows (with a few extra simple features that were not required here):
        /inch { 72 mul } def
      /Times-Bold findfont 2 inch scalefont setfont
      /Logo { (NEAL) } def
      /makegray {
         newpath 0 0 moveto
         8.5 inch 0 rlineto 0 11 inch rlineto 8.5 inch neg 0 rlineto
         closepath fill
      } def
      /start {  % starting coords to center Logo
         8.5 inch 2 div
         Logo stringwidth pop 2 div sub % x coordinate
         11 inch 2 div 50 sub % y coordinate
      } def
      0.5 setgray
      makegray
      1 setgray start moveto Logo true charpath fill
      0 setgray start moveto Logo true charpath stroke
      
      showpage
      

  5. Topics from C, C++, and Java:

    Generic constructs in C, C++, and Java:

    1. Consider C++ templates. What are its advantage(s) compared with other generic methods (in C and Java)? What are disadvantage(s) of template?

    2. From an object-oriented point of view, what is wrong with using an arbitrary Object in Java and using instanceof to decide what type of object it is?

  6. The Prolog Language:

      Consider Prolog facts and rules at the following link, an example from class about CS courses: Course example.

    1. What happens when the following is entered (after loading in the example facts and rules), followed by typing ";" over and over?
      The following shows the result.
        
        medusa% pl
        ?- consult(courses).
        courses compiled, 0.01 sec, 8,676 bytes.
        
        Yes
        ?- spring_2003_courses(X, Y, wagner).
        
        X = cs3723
        Y = 1200-mwf ;
        
        X = cs4363
        Y = 1000-mwf ;
        
        No
        

      Suppose the following additional rule is included in the source:

          course_and_office(Course, Fac, Office) :- 
               spring_2003_courses(Course, _ , Fac),
               faculty(Fac, _, Office).
        
    2. Give the meaning of the symbol :- in this rule. "in case", or "is implied by". Give the meaning of the main comma between the two parts (not the commas inside parentheses). The comma means "and".

    3. What happens when the following is entered, followed by typing ";" over and over. Result shown below
        
        ?- course_and_office(X, Y, Z).
        
        X = cs3233
        Y = tian
        Z = 'SB 3.02.00 ' ;
        
        X = cs3343
        Y = kwek
        Z = 'SB 3.02.01E' ;
        
        X = cs3723
        Y = wagner
        Z = 'SB 3.02.16 ' ;
        
        X = cs3733
        Y = srobbins
        Z = 'SB 3.02.01A' 
        (and so forth, with many more examples)
        
      What new facts does the additional rule provide? Facts about course, faculty member, and office as shown above. What is the term from relational database theory for this type of operation? This is the relational join.

    4. Consider the first set of facts about courses, starting with
        spring_2003_courses(cs3233, 1230-tr,  tian).
        
      Give at least three reasons why one would not want to include the office number of the faculty member as part of this fact, producing facts that would look like:
        spring_2003_courses(cs3233, 1230-tr,  tian, 'SB 3.02.00').
        
      Here are the problems as described in a database book by J. Ullman:
      1. Redundancy. The office number is repeated once for each course taught by an instructor. (In particular, this wastes space.)
      2. Potential inconsistency (update anomalies).As a consequence of the redundancy, we could update the office number in the record for one course, while leaving it fixed in another. Thus we would not have a unique office number for each faculty member, leaving the database in an inconsistent state, a potentially bad outcome. We can also view this as an update difficulty, since to do a proper update it is necessary to change all copies of the office number.
      3. Insertion anomalies. We cannot record an office number for a faculty member who is not teaching at least one course. (Also, the ways of forcing this have other bad side effects.)
      4. Deletion anomalies. The inverse of problem c. above is that should we delete all the courses taught by a faculty member, we unintentionally lose track of the faculty member's office number.

    5. Write a rule for facts named tr_at_1230 that would provide the faculty name, and office for faculty teaching a course at 12:30 pm on TR.
      tr_at_1230(Fac, Office) :- spring_2003_courses(_, 1230-tr, Fac),
        faculty(Fac, _, Office).
      
      Assuming this new rule is incorporated into the set of rules, then the following would result from a query:
      ?- tr_at_1230(X, Y).
      
      X = tian
      Y = 'SB 3.02.00 ' ;
      
      X = srobbins
      Y = 'SB 3.02.01A' ;
      
      No