Computer Science 3 - 2015 - Test 1 - Parva and some other tools

This should take no longer than 45 minutes and is simply intended to probe whether you have understood the material in the prac questions and the early part of the course. Answer on the question sheet (3 sides).

"The purpose of computing is insight, not numbers" (Richard Hamming)

1. You should get this right! Mine is Pat Terry, 63T0844. What is yours - in the same format? [2]

Pat Terry, 63T0844. Student name and student number! And it is genuine. Note that your student number normally just has two digits (63) for the year of first registration, the initial letter of the surname, and a four digit number for the number of applications that had been received when yours was processed. the number is often quoted with a further leading 6 (as in 663T0844), but this is a hangover from the days when we had campus 6 (Grahamstown) and campus 8 (East London). No, I don't know, so don't ask!

2. In the practical sessions you (should) have used the Parva2 translator. This was developed at Rhodes by using a compiler generator program called CoCo to produce its C# source code from a so-called "Attribute Grammar" written in a specification language called Cocol, which you will meet in a few weeks' time. This C# code was then compiled with the C# compiler CSC.exe available for the PC. Draw T-diagrams that describe this development. [6]

      ┌──────────────────────────┐          ┌──────────────────────────┐         ┌─────────────────────────┐
      │          P2C#.atg        │          │         P2C#.cs          │         │        P2C#.exe         │
      │ Parva  ──────────>  C#   │          │ Parva  ──────────>   C#  │         │ Parva  ────────>   C#   │
      │                          │          │                          │         │                         │
      └───────┐          ┌───────┴──────────┴───────┐          ┌───────┴─────────┴───────┐         ┌───────┘
              │          │         Coco.exe         │          │                         │         │
              │   Cocol  │ Cocol   ────────>    C#  │   C#     │   C#   ────────> Intel  │  Intel  │
              │          │                          │          │                         │         │
              └──────────┴───────┐          ┌───────┴──────────┴───────┐         ┌───────┼─────────┤
                                 │          │                          │         │       │  Intel  │
                                 │  Intel   │                          │  Intel  │       └─────────┘
                                 ├──────────┤                          ├─────────┤
                                 │  Intel   │                          │  Intel  │
                                 └──────────┘                          └─────────┘

3. Here is a simple Parva program (assume it is stored in the file Silly.pav and that the compiler can recognise the % operator):

    void Main() {
    // A rather simple Parva program - but what does it calculate?
      int a, b;
      read("Supply a and b (0 stops) ", a, b);  /*  first pair of data */
      while (a != 0) {
        write(a, b, a / b, a % b);
        read(a, b);                             // read the next data pair
      }
    } // Main

(a) What does it attempt to calculate and print? [2]

Very few people really got this succinctly. It does not just print one set of four numbers. It "reads a sequence of pairs of numbers, terminated by the pair (0, 0) and reflects the pair and the quotient and remainder when the first of each pair is divided by the second of the pair, using integer operations". "Modulus" is not as descriptive as "remainder" here.

(b) If you were to translate this program to C# using the Parva2ToCSharp program, it would produce the following code (Silly.cs):

    using Library;

    class Silly {

      static public void Main(string[] args) {
        int a, b;
        { IO.Write("Supply a and b (0 stops) "); a = IO.ReadInt(); b = IO.ReadInt(); }
        while (a != 0) {
          { IO.Write(a); IO.Write(b); IO.Write(a / b); IO.Write(a % b); }
          { a = IO.ReadInt(); b = IO.ReadInt(); }
        }
      } // Main
    } // Silly

This seems to have lost something (the comments) and gained something (extra, apparently unnecessary, braces { } ) - it might be preferable to have generated code like this:

    using Library;

    class Silly {

      static public void Main(string[] args) {
      // A rather simple Parva program - but what does it calculate?
        int a, b;
        IO.Write("Supply a and b (0 stops) ");
        a = IO.readInt(); b = IO.readInt();     /*  first pair of data */
        while (a != 0) {
          IO.Write(a); IO.Write(b); IO.Write(a / b); IO.Write(a % b);
          a = IO.ReadInt(); b = IO.ReadInt();    // read the next data pair
        }
      } // Main
    } // Silly

(c) Is the loss of the comments critical? Why, or why not? [2]

The loss of the comments is not critical. Compilers ignore comments in any case, and since the usual use of a tool like this, once you can trust it, is to feed the generated C# into the C# without a human reading it. the comments become irrelevant except in the original source.

(d) Might the extra { braces }, in fact, be necessary in such translations? Explain! [4]

Yes, but you have to be quite astute to see why. The apparently redundant { braces } in this example preserve the atomicity of the translated read and write statement, which in Parva can have multiple parameters, unlike the single-parameter ones in the IO library. In the above example they don't matter, but consider the example:

       Expressed in Parva                  which becomes, in C#, if the braces are discarded

       if (a > b)                          if (a > b)
           write(a, b, a/b);                   IO.Write(a);
                                           IO.Write(b);
                                           IO.Write(c);

4. Question 2 mentions four systems programs. Classify each one as being either (a) a native code compiler (b) an interpretive compiler (c) an interpreter (d) a high-level compiler (e) an assembler or (f) a decompiler. [4]

(a) Parva2ToCSharp (d) high level compiler

(b) Parva          (b) interpretive compiler

(c) CSC            (a) native code compiler

(d) CoCo           (d) high level compiler

5. A reminder of the methods in the IntSet class appears below.

    public class IntSet {
      public IntSet()
      public IntSet(BitSet s)
      public IntSet(params int[] members) {
      public void Incl(int i)
      public void Excl(int i)
      public bool Contains(int i)
      public bool IsEmpty()
      public int Members()
      public IntSet Union(IntSet otherSet)
      public IntSet Intersection(IntSet otherSet)
      public IntSet Difference(IntSet otherSet)
      public void Write()
      public string ToString()
    } // IntSet

The code below shows a C# version of a Sieve program for counting the number of primes below a limit read in as data. Show how it could be modified to make use of the IntSet class, in place of the Boolean array it currently uses. It will suffice to mark the changes on the code; there is no need to write out all the code again. [5]

     using Library;

     class Sieve {

       public static void Main (String [] args) {
         IO.write("Supply largest number to be tested ");
         int n = IO.ReadInt();
         bool [] Uncrossed = new bool [n];
         int primes = 0;
         for (int i = 2; i <= n; i++) {
           Uncrossed[i] = true;
         }
         for (int i = 2; i <= n; i++) {
           if (Uncrossed[i]) {
             primes++;
             int k = i;
             do {
               Uncrossed[k] = false;
               k += i;
             } while (k <= n);
           }
         }
         IO.Write(primes + " primes between 1 and " + n);
       } // Main
     } // Sieve

Here is one, pretty direct, solution

     using Library;

     class Sieve {

       public static void Main (String [] args) {
         IO.write("Supply largest number to be tested ");
         int n = IO.ReadInt();
         IntSet Uncrossed = new IntSet();
         int primes = 0;
         for (int i = 2; i <= n; i++) {
           Uncrossed.Incl(i);
         }
         for (int i = 2; i <= n; i++) {
           if (Uncrossed.Contains(i)) {
             primes++;
             int k = i;
             do {
               Uncrossed.Excl(k);
               k += i;
             } while (k <= n);
           }
         }
         IO.Write(primes + " primes between 1 and " + n);
       } // Main
     } // Sieve

but, as usual, it can be done even more simply!

     using Library;

     class Sieve {

       public static void Main (String [] args) {
         IO.write("Supply largest number to be tested ");
         int n = IO.ReadInt();
         IntSet Crossed = new IntSet();  // or IntSet(n)
         int primes = 0;
         for (int i = 2; i <= n; i++) {
           if (!Crossed.Contains(i)) {
             primes++;
             int k = i;
             do {
               Crossed.Incl(k);
               k += i;
             } while (k <= n);
           }
         }
         IO.Write(primes + " primes between 1 and " + n);
       } // Main
     } // Sieve


Home  © P.D. Terry