CS 3723/3731 Programming Languages
Final Exam, Fall 2003, Selected Answers

  1. Formal Grammars and Languages:

    Consider the following grammar that was part of one of the recitations.

    1. Which are the terminal symbols?a b ( )
      Which are the non-terminal symbols?S M L
      Which are the meta-symbols?--->

    2. Give the parse tree for the sentence. (You should construct this parse tree by trial and error, or by any other means, but not using the method in the recitation involving this grammar.)

        b ( ( a a ) a ) b

    3. Which of our two parsing methods did we use in the recitation that involved this grammar? Shift-reduce (bottom-up)

    4. Give a simple way to show that a grammar is ambiguous. [In fact, the grammar above is not ambiguous.] Find a single sentence (string of terminals) with two distinct parse trees.

    5. Give one brief example of an ambiguous construct from one of the grammars that we had. [Just state the example; don't show that it is ambiguous.] The if-then and it-then-else was ambiguous, Also E ---> E+E | E*E | (E) | id

  2. Semantic Actions:

    The language represented by the grammar below consists of fully parenthesized postfix expressions:

         P   ---->  E
         E   ---->  dig | '(' E  E  Op ')'
         Op  ---->  '+' | '-' | '*'| '/' | '^'
         dig ---->  '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
    
    Here is a Java parser for the language: You are to add code to the listing above so that the program will return the correct integer values when the operations have been carried out. Here is an interactive session showing how the language works and showing what your code should do. Each input is a single expression, either just a constant or a parenthesized expression starting with two similar expressions and ending with an operator.
    1. What does fully parenthesized mean? There is no need for precedence or associativity rules; all such choices are resolved with explicit parentheses.

      What does postfix mean? The operators come at the right.

    2. Evaluate the expression
        ((2 4 ^) ( (8 2 /) (5 3 -) *) +)
        
      carefully by hand and show that 24 is the correct answer.

    3. Does this parser use an early or a late scanning stategy? What does this mean in terms of recognizing an expression? (No credit for just guessing "early" or "late".) This uses "late" scanning, meaning to do the scan as late as possible (rather than as early as possible). This is important here because when one encounters the top-level ")" to end an expression, the parser is not looking for another token.

    4. Supply the additional code needed to do the evaluation. If you wish, you may use the evaluating function below. (If you don't know any java, you can still do this problem by just pretending that you are coding in C, since for this application the two languages are nearly identical.)
           private int eval(int r1, int r2, char op) {
              switch (op) {
                 case '+': return r1 + r2;
                 case '-': return r1 - r2;
                 case '*': return r1 * r2;
                 case '/': return r1 / r2;
                 case '^': int res = r1;
                              while (r2 != 1) {
                                 res = res*r1; r2--;
                              }
                           return res;
                 default: 
                    error(4);
                    return 0;
              }
           } 
        
      Answer:
        /* Evaluate.java: parser with exam question grammar:
         *   P   ---->  E
         *   E   ---->  dig | '(' E  E  Op ')'
         *   Op  ---->  '+' | '-' | '*'| '/' | '^'
         *   dig ---->  '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
         */
        import java.io.*;
        
        public class Evaluate {
           private char next; // = ' ';
        
           // P: recognize a program
           public int P() {
              return E();
           }
        
           // E: recognize a statement
           private int E() {
              scan();
              int res = 0, res1, res2;
              if (Character.isDigit(next)) {
                 res = next - '0';
              }
              else if (next == '(') {
                 res1 = E();
                 res2 = E();
                 scan();
                 res = eval(res1, res2, next);
                 scan(); // for the ')'
                 if (next != ')') error(1);
              }
              else error(3);
              return res;
           }
        
           private int eval(int r1, int r2, char op) {
              switch (op) {
                 case '+': return r1 + r2;
                 case '-': return r1 - r2;
                 case '*': return r1 * r2;
                 case '/': return r1 / r2;
                 case '^': int res = r1;
                              while (r2 != 1) {
                                 res = res*r1; r2--;
                              }
                           return res;
                 default: 
                    error(4);
                    return 0;
              }
           }
        
           private void scan() {
              do {
                try {
                    next = (char)System.in.read();
                } catch (IOException e){
                   error(2);
                }
              } while ( next == ' ' || next == '\n');
           }
        
           // error: error encountered during the parse
           private void error(int n) {
              System.out.println("ERROR " + n + ", Token: " + next );
              System.exit(1);
           }
        
           public static void main(String[] args) {
              Evaluate evaluate = new Evaluate();
              System.out.println(evaluate.P());
           }
        }
        
  3. The Lisp Language:

    1. In each case say what the Lisp interpreter would produce when it evaluates the given input (there are no errors):

    2. Explain why each of the following inputs is in error when evaluated by Lisp. Explain in each case exactly what the error is (not what the error message, if any, is).

      Answers:

             
        > 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
        > (car (cdr '(a b c))
           )
        B
        > (car (car '(a b c)))
        >>Error: The value of X, A, should be a LIST
        
        CAR
           Required arg 0 (X): A
        
        > (append (a b c) (d e f))
        >>Error: The function A is undefined
        
        > (quit)
        
    3. Write a Lisp function switch that will take a two-element list as input and returns a list with these elements in the opposite order. (This function does not use recursion. You are not allowed to use the built-in Lisp function reverse.) For example,
        > (defun switch (x)
             ( cons (car (cdr x)) (list (car x))))
        SWITCH
        
        > (switch '(a b))
        (B A)
        > (switch '((a) (b c)))
        ((B C) (A))
                 

    4. Write a recursive Lisp function remove that removes all occurrences of an element from a list. For example,
        > (defun remove (e x)
             (cond  ((null x) nil)
                    ((equal e (car x)) (remove e (cdr x)))
                    (t (cons (car x) (remove e (cdr x))))))
        REMOVE
        > (remove 'a '(a b c a b))
        (B C B)
        > (remove 'a '(a a a))
        NIL
        > (remove 'a '(a))
        NIL
        > (remove 'a '(b c d))
        (B C D)
        > (remove '(a b) '(a (a b) c (a b) d (a b))
        (A C D)
                 

  4. The Postscript Language:

    Consider the following two Postscript programs:

    /Times-Roman findfont
       20 scalefont setfont
    /inch { 72 mul} def
    /square {
    
       newpath
          0 0 moveto
          1 inch 0 rlineto
          0 1 inch rlineto
          -1 inch 0 rlineto
       closepath fill
       0.1 inch 1.1 inch moveto
       (A Box) show
    } def
    
    square
    4 inch 2 inch translate
    60 rotate
    square
    4 inch 2 inch translate
    60 rotate
    square
    
    showpage
    
      
      /inch { 72 mul} def
      /square { % stack: side => ---
         /side exch def
         newpath
            0 0 moveto
            side 0 rlineto
            0 side rlineto
            side neg 0 rlineto
         closepath fill
      
      
      } def
      
      1 inch square
      4 inch 2 inch translate
      60 rotate
      1.5 inch square
      4 inch 2 inch translate
      60 rotate
      2 inch square
      
      showpage
      
      

    1. Use a sketch to show exactly what the program on the left will print. [Hint: remember that Postscript uses degrees for angles and that a positive angle is clockwise.] About the same as in the Blue book, page 49.

    2. The program on the right is a slight variation. It uses a parameter. Again sketch what the program on the right will print. Then explain exactly how the parameter is handled. Here the parameter gives increasingly larger square, though oriented the same. The code "/side exch def" gives side the value that was on top of the stack.

    3. Replace the 7 lines before showpage on the left with

        0 1 20 { pop square 1.5 inch 0.5 inch translate 45 rotate 0.5 sqrt dup scale % scale factor: 0.707 } for

      Say approximately what will be printed with this replacement. This will be a spiral picture of 21 squares of decreasing size, similar to an example from class.

    4. Consider the following Postscript code, which prints UTSA starting at (0, 0).

        /Times-Roman findfont 100 scalefont setfont
        0 0 moveto
        (UTSA) show
        showpage
        

      Rewrite this code so that is prints the UTSA 5 inches up from the bottom, and exactly centered horizontally on the page. [Hints: The page is 8.5 inches wide. There are 72 points to an inch. The Postscript code (UTSA) stringwidth pop will give the horizontal extent of the string.] Here is an answer:

        /Times-Roman findfont 100 scalefont setfont /inch {72 mul} def 8.5 inch 2 div (UTSA) stringwidth pop 2 div sub 5.5 inch moveto (UTSA) show showpage