Computer Science 301 - 2005 - Using Coco/R

(This example is based on a problem set in an examination some years back. In the examination, candidates were given the basic grammar and asked to suggest the actions that had to be added.)

As you should be aware, IP addresses as used in Internet communication are typically expressed in "dotted quad" form, as exemplified by 146.231.128.6. The IP address actually represents a 32 bit integer; the four numbers in the quadruple corresponding to successive 8 bit components of this integer. For humans, machine addressing is usually more memorable when expressed in "DNS" format, as exemplified by terrapin.ru.ac.za. Some systems maintain tables of matching addresses, for example

         146.231.122.131   bungee.ru.ac.za       #comments appear like this
         146.231.128.6     terrapin.ru.ac.za
         146.231.56.10     thistle-sp.ru.ac.za
         147.28.0.62       psg.com

When we moved our CS and IS departments to new premises in Hamilton on the famous 9/11 in 2001, a decision was made to rename and uniquely renumber all the many machines in our possession. Our system administrators tried to draw up a table like the one above, which was then merged with the existing table in the IT division. Unfortunately, a few mistakes were made, which caused havoc until they were ironed out. For example, there were lines reading

         146.231.122.1123  pdt1.ict.ru.ac.za     #invalid IP address
         146.231.122.156   pdt2.ict.ru.ac.za
         146.231.122.156   pdt3.ict.ru.ac.za     #non-unique IP address

How could you use Coco/R to build a system to enable a file in this format to be checked quickly, and the errors identified.

One solution shows how parameters may be passed between parsing methods, and the other how static variables in the parser class may be accessed from several methods:

    import Library.*;
    import java.util.*;

    COMPILER Check1 $CN
    // Put your names and a description here
    // This version uses parameters

    IGNORECASE
    CHARACTERS
      digit   = "0123456789" .
      letter  = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .
      eol     = CHR(10) .
    TOKENS
      number = digit { digit } .
      name   = letter { letter | digit | "." | "-" } .
    COMMENTS FROM "#" TO eol
    IGNORE CHR(0) .. CHR(31)
    PRODUCTIONS
      Check1                        (. ArrayList IPList = new ArrayList(); .)
      = { Entry<IPList> } EOF       (. if (Successful()) IO.writeLine("all correct"); .) .

      Entry<ArrayList IPL>
      = IPNumber<IPL> name .

      IPNumber<ArrayList IPL>
      =                             (. int n, m; .)
      Number<out n>
      "." Number<out m>             (. n = 256 * n + m; .)
      "." Number<out m>             (. n = 256 * n + m; .)
      "." Number<out m>             (. n = 256 * n + m;
                                       if (IPL.contains(new Integer(n))) SemError("duplicate IP number");
                                       else IPL.add(new Integer(n)); .) .

      Number<out int n>
      =  number                     (. try {
                                         n = Integer.parseInt(token.val);
                                         } catch (NumberFormatException e) {
                                         n = 256;  // illegal anyway
                                         }
                                       if (n > 255) SemError("number too large"); .) .
    END Check1.


    import Library.*;
    import java.util.*;

    COMPILER Check2 $CN
    // Put your names and a description here
    // This version uses a static Arraylist, but no parameters

    static ArrayList IPList = new ArrayList();

    IGNORECASE
    CHARACTERS
      digit   = "0123456789" .
      letter  = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .
      eol     = CHR(10) .
    TOKENS
      number = digit { digit } .
      name   = letter { letter | digit | "." | "-" } .
    COMMENTS FROM "#" TO eol
    IGNORE CHR(0) .. CHR(31)
    PRODUCTIONS
      Check2
      = { Entry } EOF               (. if (Successful()) IO.writeLine("all correct"); .) .

      Entry
      = IPNumber name .

      IPNumber
      =                             (. int n, m; .)
      Number<out n>
      "." Number<out m>             (. n = 256 * n + m; .)
      "." Number<out m>             (. n = 256 * n + m; .)
      "." Number<out m>             (. n = 256 * n + m;
                                       if (IPList.contains(new Integer(n))) SemError("duplicate IP number");
                                       else IPList.add(new Integer(n)); .) .


      Number<out int n>
      =  number                     (. try {
                                         n = Integer.parseInt(token.val);
                                         } catch (NumberFormatException e) {
                                         n = 256;  // illegal anyway
                                         }
                                       if (n > 255) SemError("number too large"); .) .

    END Check2.


As you may know, multiple names may be given to a host (associated with one IP number) on the Internet. On the basis that we might wish to do this for the computers in our building, but still only assign each name once, extend the application so that it might react sensibly to data of a form exemplified below.

          146.231.122.131   bungee.ru.ac.za       #comments appear like this
                            humfac.ru.ac.za       #alternative name
                            www.humfac.ru.ac.za   #and yet another name
          146.231.122.75    bungee.ru.ac.za       #invalid - name already used
          146.231.128.6     terrapin.ru.ac.za
          146.231.56.10     thistle-sp.ru.ac.za
          147.28.0.62       psg.com
          147.28.0.67       psg.com               #invalid - name already used
          146.231.122.1123  pdt1.ict.ru.ac.za     #invalid IP address
          146.231.122.156   pdt2.ict.ru.ac.za
          146.231.122.156   pdt3.ict.ru.ac.za     # non-unique IP address

This is not hard to do. Use the ArrrayList class to create two different lists.


Using parameters:

    PRODUCTIONS
      Check3                        (. ArrayList
                                         IPList = new ArrayList(),
                                         NameList = new ArrayList(); .)
      =
      { Entry<IPList, NameList> }
      EOF                           (. if (Successful()) IO.writeLine("all correct"); .) .

      Entry<ArrayList IPL, ArrayList NL>
      = IPNumber<IPL> Name<NL> { Name<NL> } .

      Name<ArrayList NL>
      = name                        (. String s = token.val;
                                       if (NL.contains(s)) SemError("duplicate computer name");
                                       else NL.add(s); .) .

      IPNumber<ArrayList IPL>
      =                             (. int n, m; .)
      Number<out n>
      "." Number<out m>             (. n = 256 * n + m; .)
      "." Number<out m>             (. n = 256 * n + m; .)
      "." Number<out m>             (. n = 256 * n + m;
                                       if (IPL.contains(new Integer(n))) SemError("duplicate IP number");
                                       else IPL.add(new Integer(n)); .) .

      Number<out int n>
      =  number                     (. try {
                                         n = Integer.parseInt(token.val);
                                         } catch (NumberFormatException e) {
                                         n = 256;  // illegal anyway
                                         }
                                       if (n > 255) SemError("number too large"); .) .
    END Check3.


Alternatively we could dispense with parameter passing:

    static ArrayList
      IPList = new ArrayList(),
      NameList = new ArrayList();
    ...

    PRODUCTIONS
      Check4
      = { Entry } EOF               (. if (Successful()) IO.writeLine("all correct"); .) .

      Entry
      = IPNumber Name { Name } .

      Name
      = name                        (. String s = token.val;
                                       if (NameList.contains(s)) SemError("duplicate computer name");
                                       else NameList.add(s); .) .

      IPNumber
      =                             (. int n, m; .)
      Number<out n>
      "." Number<out m>             (. n = 256 * n + m; .)
      "." Number<out m>             (. n = 256 * n + m; .)
      "." Number<out m>             (. n = 256 * n + m;
                                       if (IPList.contains(new Integer(n))) SemError("duplicate IP number");
                                       else IPList.add(new Integer(n)); .) .

      Number<out int n>
      =  number                     (. try {
                                         n = Integer.parseInt(token.val);
                                         } catch (NumberFormatException e) {
                                         n = 256;  // illegal anyway
                                         }
                                       if (n > 255) SemError("number too large"); .) .
    END Check4.


Home  © P.D. Terry