Computer Science 3 - 2002

Programming Language Translation


Practical for Week 11, beginning 29 April 2002

This prac is due for submission by lunch time on your next practical day, correctly packaged in a transparent folder as usual. Pracs should please be deposited in the hand-in box outside the lab. Only one set of listings is needed for each group, but please enclose as many copies of the cover sheet as are needed, one for each member of the group. These will be returned to you in due course.


Objectives

Ja, well, no, fine. All you folks who thought this was a bit of a jorl so far, think again. But the objectives of this practical are to allow you to learn how to get Coco/R to do most of the work in writing syntax directed systems. Cheer up - it's not as bad as it might appear!


To hand in:

This week you are required to hand in, besides the cover sheet:

I do NOT require listings of any C++ code produced by Coco/R.


Task 1 Buy the kit (for free!)

In the kit PRAC11.ZIP you will find some goodies than usual. And you might find it useful to visit the web page at http://www.cs.ru.ac.za/CSc301/Translators/cocotips.htm.


Task 2 - Study the handout (that will cost you!)

(This task is based on a problem set in last year's examination. In the examination, candidates were given the 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 decimal" 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.13      cspt1.ict.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 last year, 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.11235   cspt1.ict.ru.ac.za    #invalid IP address
         146.231.122.15      cspt2.ict.ru.ac.za
         146.231.122.15      cspt3.ict.ru.ac.za    # non-unique IP address

The ATG file below shows how Coco/R might be used to develop a system that would enable a file in this format quickly to be checked and the errors identified.

    COMPILER Check $XCN

    #include "check.h"

    IGNORE CASE
    IGNORE CHR(1) .. CHR(31)

    CHARACTERS
      digit   = "0123456789" .
      letter  = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .
      eol     = CHR(10) .

    COMMENTS FROM "#" TO eol

    TOKENS
      number = digit { digit } .
      name   = letter { letter | digit | "." | "-" } .

    PRODUCTIONS
      Check
      =                         (. IPList L; .)
      { Entry<L> }
      EOF                       (. if (Successful()) printf("\n all correct"); .)
      .

      Entry<IPList &L>
      = IPNumber<L> name .

      IPNumber<IPList &L>
      =                         (. long n, m; .)
      Number<n>
      "." Number<m>             (. n = 256 * n + m; .)
      "." Number<m>             (. n = 256 * n + m; .)
      "." Number<m>             (. n = 256 * n + m;
                                   if (L.isMember(n)) SemError(1001);
                                   else L.add(n); .) .

      Number<long &n>
      =                         (. char str[100] .)
      number                    (. LexString(str, sizeof(str) - 1);
                                   n = atoi(str);
                                   if (n > 255) SemError(1000); .) .
    END Check.

Start off by studying this grammar carefully, and then making and executing the program.

To make and run the program proceed as you did in an earlier practical, for example

GENMAKE CHECK BORL55
MAKE -f CHECK.MAK
CHECK IPLIST

Please ask the demonstrators if there are things you don't understand in the grammar.


Task 3 Extending the application

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.13    cspt1.ict.ru.ac.za    #comments appear like this
                     scifac.ru.ac.za       #another name for it
                     www.scifac.ru.ac.za   #and yet another
   146.231.128.6     terrapin.ru.ac.za
   147.28.0.62       psg.com
   147.28.0.67       psg.com               #invalid - name already in use
   146.231.122.1123  cspt1.ict.ru.ac.za    #invalid - bad IP address
   146.231.122.15    cspt2.ict.ru.ac.za
   146.231.122.15    cspt3.ict.ru.ac.za    #invalid - non-unique IP address

Hint: This is not hard to do. You should use the List template to create two different lists. You will need to add a bit to the grammar, edit check.h, and add to check.frm.


Task 4 - Towards marketing a versatile calculator

All you have ever wanted - turn an enormous Wintel machine into a calculator!

Since the question in Practical 9 dealing with extended expression grammars in Parva was not very well done, let us try to reinforce the concepts by constructing a calculator that can (a) deal with Boolean or Integer expressions (b) store and retrieve values in variables of the user's choice (c) guard against mixed-mode errors (such as dividing Boolean values or applying the NOT operator to an integer value). This is complex, so do it in stages:

A grammar describing the input to such a calculator (CALC.ATG) appears below. The hierarchy of the set of productions for Expression imposes a precedence ordering on operators similar to the one used in C++/Java.

  COMPILER Calc $XNC
  //  Put your names and a description here

  IGNORE CHR(1) .. CHR(9) + CHR(13) ..  CHR(31)

  CHARACTERS
    digit      = "0123456789" .
    letter     = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .
    eol        = CHR(13) .

  TOKENS
    number     = digit { digit } .
    identifier = letter { letter | digit } .
    EOL        = eol .

  PRODUCTIONS
    Calc       = { Print | Assignment } "quit" .

    Assignment = Variable "=" Expression SYNC ";" .
    Print      = "print" Expression { WEAK ","  Expression } SYNC ";" .

    Expression = AndExp { "||" AndExp } .
    AndExp     = OrExp  { "&&" OrExp } .
    OrExp      = AddExp [ RelOp AddExp ] .
    AddExp     = MultExp { AddOp MultExp } .
    MultExp    = UnaryExp { MulOp UnaryExp } .
    UnaryExp   = Factor | "+" UnaryExp | "-" UnaryExp | "!" UnaryExp .
    Factor     = Variable | Number | "true" | "false" | "(" Expression ")" .
    Variable   = identifier .
    Number     = number .
    MulOp      = "*" | "/" | "%"  .
    AddOp      = "+" | "-" .
    RelOp      = "==" | "!=" | "<" | "<=" | ">" | ">=" .

  END Calc.

To make up a parser proceed in the usual way

GENMAKE CALC BORL55
MAKE -f CALC.MAK
CALC CALC.TXT

If you do that the results will not be very interesting - you will be able to parse expressions, and detect syntactically incorrect expressions, but not much more.

Add actions to this grammar so that it will be able to evaluate the expressions. To start with, assume that expressions will not make use of any "variables". (CALC.ATG is already "spread out" to help in this regard).

Hints:

Bonus: Can anything go wrong in evaluating simple expressions? If so, how do you detect the fact and report it?


Task 5

Extend the system so that values can be stored in and retrieved from variables.

Hints:


Task 6

Just because in C++ you can mix integer and Boolean operands in almost any way in expressions does not mean that this is sensible. Extend your system so that it keeps track of the types of operands and expressions, and forbids mixing of the wrong types.

Hint: You might like to define an enumeration

enum TYPES { none, ints, bools };

to represent the various types that might be encountered. ints and bools are associated with correctly formed and defined operands and expressions, while none can be associated with expressions and operands where the type is incorrect. Thus for example

      4 + 5                is of type  ints
      true || false        is of type  bools
      4 == 5               is of type  bools
      4 && 5               is of type  none
      (4 == 5) && !false   is of type  bools


Generic List Template Class

  /* Simple generic linked list template class. (Interface only)
     Closely based on one by George Wells  --  27 February 1996
     Modifications by Pat Terry -- April 2002 */

  template<class T> class List
    { public:
        List (void);                               // Constructor
        List (const List& lst);                    // Copy constructor
        ~List (void);                              // List destructor
        void add (T item, int position = INT_MAX); // Place new item in a List
        void remove (int position, T &item);       // Remove item at position in List
        int length (void);                         // Return number of elements in List
        T& operator[] (int index);                 // Subscript a List
        int position (T item);                     // Return position item in a List (or -1)
        int isMember (T item);                     // True if item is in List
        int isEmpty ();                            // Return true if list has no members
    }; // class List


// Demonstration program showing simple (integer) use of the List class // P.D. Terry, Rhodes University, 2002 #include "misc.h" #include "list.h" typedef List<int> INTLIST; void AddElements (INTLIST &List) { // Add some even numbers into List for (int i = 0; i < 10; i+=2) List.add(i); } void main (void) { INTLIST myList; AddElements(myList); // add some even numbers printf("length = %d\n", myList.length()); // how many went in? for (int i = 0; i < 12; i++) // see which numbers are present printf("%d %d\n", i, myList.isMember(i)); for (int j = 0; j < myList.length(); j++) // show indexing capability printf("%d ", myList[j]); printf("\n"); int d; while (!myList.isEmpty()) { // take out elements from front myList.remove(0, d); printf("%d ", d, myList.length()); } }


// Demonstration program showing simple (structure) use of the List class // with static (perhaps wasteful) allocation of strings // P.D. Terry, Rhodes University, 2002 #include "misc.h" #include "list.h" struct myStruct { char str[1000]; // the lookup (key) field int len; // the length of the string // "I get by with a little help from my friends" friend int operator == (myStruct x, myStruct y) { return strcmp(x.str, y.str) == 0; } friend int operator != (myStruct x, myStruct y) { return strcmp(x.str, y.str) != 0; } }; typedef List<myStruct> StructList; void AddElements (StructList &List) { // Add some structures into List myStruct S; for (int i = 0; i < 4; i++) { gets(S.str); // from stdin S.len = strlen(S.str); // set length attribute printf("%s\n", S.str); // echo for user List.add(S); } } void main (void) { StructList myList; AddElements(myList); // add some structures printf("length = %d\n", myList.length()); // how many went in? myStruct S; // test membership strcpy(S.str, "Hello"); printf("%s %d\n", S.str, myList.isMember(S)); for (int j = 0; j < myList.length(); j++) // show indexing capability printf("%s\n", myList[j].str); printf("\n"); while (!myList.isEmpty()) { // take out elements from front myList.remove(0, S); printf("%s | %d\n", S.str, S.len); } }


Home  © P.D. Terry