Computer Science 301 - 2010 - Test on Week 24 - Solutions

You may use your notes, or refer to material on the website if you like. Keep your solutions as simple as possible! Answer on the question sheet (4 sides)

Many people did this really well; but those who did not really crashed badly. Please study these solutions carefully.

1. Some people never remember, no matter how often you remind them - What is your name (surname)? [1]

Pat (Terry) 63T0844

2. The grammar below attempts to describe your present hard-working lifestyle.

    COMPILER Prac $CN
    /* Describe progress of a compiler practical */

    CHARACTERS
      letter  = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .
    TOKENS
      name = letter { letter } .
    IGNORE CHR(0) .. CHR(31)

    PRODUCTIONS
      Prac         = Handouts { Task } "Submit" .
      Handouts     = "PracSheet" { "HintSheet" } .
      Task         = "Attempt" { ConsultTutor  "Attempt" }  .
      ConsultTutor = name .
    END Prac.

As you know, we sometimes have trouble finding tutors. As you may not know, we are going to have problem paying them, because they have recently told me that they want to be paid a fee for each occasion they are consulted. So what I need now is a list of tutors with a count of such occasions for each one. What must I add to the grammar to produce me such a list?

A typical list might be as follows (it does not have to be in alphabetic order):

       Joao       12
       Etienne    10
       Pat        45

Here is a solution using an ArrayList that contains objects of a simple Tutor class. The list is declared static for simplicity:

    import java.util.*;
    import library.*;

    COMPILER Prac $CN
    /* Determine how often each tutor has been consulted during a practical
       P.D. Terry, Rhodes University, 2010 */

    static class Tutor {
      public String name;
      public int count;

      public Tutor(String name, int count) {
        this.name = name; this.count = count;
      }

      public void writeLine() {
        IO.write(this.name, -14);
        IO.writeLine(this.count);
      }

    } // Tutor

    static ArrayList<Tutor> list = new ArrayList<Tutor>();  // global for simplicity here!

    static int position(String name) {
    // Finds position of entry with search key name in list, or -1 if not found
      int i = list.size() - 1;                              // index of last entry
      while (i >= 0 && !name.equals(list.get(i).name))      // short-circuit protection
        i--;                                                // will reach -1 if no match
      return i;
    }


    CHARACTERS
      letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .
    TOKENS
      name   = letter { letter } .
    IGNORE CHR(0) .. CHR(31)

    PRODUCTIONS
      Prac
      = Handouts { Task }
        "Submit"           (. for (int i = 0; i < list.size(); i++)
                                list.get(i).writeLine(); .) .

      Handouts
      = "PracSheet" { "HintSheet" } .

      Task
      = "Attempt" { ConsultTutor "Attempt" } .

      ConsultTutor
      = name               (. int pos = position(token.val);
                              if (pos >= 0) list.get(pos).count++;
                              else list.add(new Tutor(token.val, 1)); .) .

    END Prac.

3. The following Cocol description is of a set of letters in envelopes ready to take to the post office.

    COMPILER Mail $CN
    /* Describe simple set of mailing envelopes */

    CHARACTERS
      control   = CHR(0) .. CHR(31) .
      digit     = "0123456789" .
      inWord    = ANY - control - digit .
      sp        = CHR(32) .

    TOKENS
      stamp     = "R" digit { digit } [ "." digit { digit } ] .
      postcode  = "postcode:" sp digit { digit } .
      word      = inWord { inWord } .
      number    = digit { digit } .

    IGNORE control

    PRODUCTIONS
      Mail      = { Envelope } EOF .
      Envelope  = Stamp { Stamp } Person Address .
      Address   = Street Town [ PostCode ] .
      Person    = word .
      Street    = [ number ] word .
      Town      = word .
      PostCode  = postcode .
      Stamp     = stamp .
    END Mail.

How would you add to this grammar so that the parser system could tell you (a) the total value of the stamps on all the envelopes (b) the names of all people whose addresses did not contain postcodes?

Here is a solution that uses parameters on the parsing methods:

    import library.*;

    COMPILER Mail1 $CN
    /* Describe simple set of mailing envelopes (Java version)
       P.D. Terry, Rhodes University, 2010 */

    CHARACTERS
      control   = CHR(0) .. CHR(31) .
      digit     = "0123456789" .
      inWord    = ANY - control - digit .
      sp        = CHR(32) .

    TOKENS
      stamp     = "R" digit { digit } [ "." digit { digit } ] .
      postcode  = "postcode:" sp digit { digit } .
      word      = inWord { inWord } .
      number    = digit { digit } .

    IGNORE control

    PRODUCTIONS
      Mail1                              (. double cost, total = 0; .)
      = { Envelope<out cost>             (. total += cost; .)
        } EOF                            (. IO.writeLine("Total cost R" + total); .) .


      Envelope<out double cost>          (. String name;
                                            double value;
                                            boolean hasCode;
                                            cost = 0; .)
      = Stamp<out value>                 (. cost += value; .)
        { Stamp<out value>               (. cost += value; .)
        } Person<out name>
        Address<out hasCode>             (. if (!hasCode) IO.writeLine(name + " has no postcode"); .) .


      Address<out boolean hasCode>
      = Street Town                      (. hasCode = false; .)
        [ PostCode                       (. hasCode = true; .)
        ] .

      Person<out String name>
      = word                             (. name = token.val; .) .

      Street   = [ number ] word .
      Town     = word .
      PostCode = postcode .

      Stamp<out double value>
      = stamp                            (. value = 0.0;
                                            try {
                                              value = Double.parseDouble(token.val.substring(1));
                                            } catch (NumberFormatException e) {
                                              SemError("number out of range");
                                            } .) .
    END Mail1.

Using parameters is really more complicated than a simple problem like this deserves! Here is a simple solution using static variables in the Parser class. Note the way in which the production for Address has been subtly modified, and an "action" attached to an "empty" alternative. This technique is amazingly useful at times.

    import library.*;

    COMPILER Mail2 $CN
    /* Describe simple set of mailing envelopes (Java version)
       This does it all with "global" variables for simplicity
       P.D. Terry, Rhodes University, 2010 */

      static double cost = 0.0;
      static String name;

    CHARACTERS
      control   = CHR(0) .. CHR(31) .
      digit     = "0123456789" .
      inWord    = ANY - control - digit .
      sp        = CHR(32) .

    TOKENS
      stamp     = "R" digit { digit } [ "." digit { digit } ] .
      postcode  = "postcode:" sp digit { digit } .
      word      = inWord { inWord } .
      number    = digit { digit } .

    IGNORE control

    PRODUCTIONS
      Mail2
      = { Envelope } EOF                 (. IO.writeLine("Total cost R" + cost); .) .

      Envelope = Stamp { Stamp } Person Address .

      Address
      = Street Town
        (   PostCode
          |                              (. IO.writeLine(name + " has no postcode"); .)
        ) .

      Person   = word                    (. name = token.val; .) .
      Street   = [ number ] word .
      Town     = word .
      PostCode = postcode .

      Stamp = stamp                      (. double value = 0.0;
                                            try {
                                              value = Double.parseDouble(token.val.substring(1));
                                            } catch (NumberFormatException e) {
                                              SemError("number out of range");
                                            }
                                            cost += value; .) .

    END Mail2.

Note the use of the try-catch block. In Java this is mandatory; in the C# version one can try to "get away" with not using a try-catch block, but that only works as long as the input is correct!

Few students realised that one would have to convert the token.val string to a double value - which was worrying, since you had seen this in the prac this week. Even fewer students realised that you would have to strip off the leading "R" before doing this conversion.

As always, if there is anything about these solutions that you do not understand, please come to ask for help. Understanding how to add actions and attributes to Cocol grammars is a critically important part of this course.


Home  © P.D. Terry