More examples of DemeterJ programs are at http://www.ccs.neu.edu/research/demeter/sources/DemeterJava/examples From dougo@ccs.neu.edu Thu Nov 14 16:09:52 1996 From: Doug Orleans Subject: a simple example in both DemeterJ and Demeter/C++ Some of you have asked me how to translate between Prof. Lieberherr's book, which uses Demeter/C++ syntax, and DemeterJ. I wrote up this small example last month, which I thought was on the Demeter web page but I can't find it. So here it is; I hope it will help a little. The Class Dictionary File ------------------------- DemeterJ accepts .cd files that are almost identical to the ones described in Karl's book. (DemeterJ allows some extensions which are not covered in the book but they are not important for simple projects.) For example: Team = Manager List(Player) [ "(" List(Player) ")" ]. Manager = "manager" String. List(X) ~ { X }. Player = Hitter | Pitcher *common* String. Hitter = "hitter". Pitcher = "pitcher". BullpenCollector = List(Pitcher). Here are some of the differences: o You can import other packages, e.g. import java.io.*; You can then refer to any imported class directly, without having to use "@@LIB" like in Demeter/C++. o Instead of using terminal classes like DemNumber, DemString, etc., you just use Integer, String, etc. from the java.lang package. One additional one is provided (in the "demeter" package, which is automatically imported): Ident; it's just a wrapper around String, but the lexer treats it slightly differently (viz., only letters, numbers, and underscores). o The LL(1) condition is lifted; because it uses a real parser generator from Sun, the syntax only needs to be LL(k), for k>0. o Instead of using "*inherits*" to explicitly designate parents, use either "*extends*" (with a single class name) or "*implements*" (with a list of interface names). The Behavior File ----------------- The .beh file is simply a list of methods (organized by class). There are three types of methods-- traversal methods: Team { traversal collectBullpen(BullpenCollector b) { bypassing -> *,disabled,* to Pitcher; } } visitor methods: BullpenCollector { before Pitcher (@ pitchers = pitchers.append(host)); @) } and regular methods, which are passed verbatim to the .java file: Main { (@ static public void main(String args[]) throws Exception { Team t = Team.parse(System.in); BullpenCollector b = new BullpenCollector(new Pitcher_List()); t.collectBullpen(b); System.out.println(b.get_pitchers()); } @) } Traversal methods and visitor methods work together to perform the same task as propagation patterns and transportation patterns; in Demeter/C++ this would be written as: *operation* void collectBullpen(Bullpen *b) *traverse* *from* Team *to* Pitcher *wrapper* Pitcher *prefix* (@ b->pitchers = b->pitchers->lisp_append(this); @) and then in main.C: void main(int argc, char *argv[]) { Team t = new Team(); t->g_parse(argv[1]); BullpenCollector b = new BullpenCollector(new Pitcher_List()); t->collectBullpen(b); b->get_pitchers()->g_print(); } The difference is that the behavior is split between traversal and non-traversal, rather than tied to the traversal. This means, among other things, that the traversal and non-traversal behavior can be encapsulated and reused; also, several visitors can be combined to operate on a single traversal in parallel. Note that visitor classes are defined in the class dictionary, just as ordinary classes. There's nothing special about them, except that they happen to have visitor methods.