(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.
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.
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.