-------------------------------------------------------------------------- Object-oriented Systems Fall 1995 COM 3360/NTU SE737 --------------------------------------------------------------------------- Assignment 5 Due date: Monday, Nov. 6 NTU: one week later --------------------------------------------------------------------------- This assignment is stored in file $OO/hw/5 in file assign.txt ========= On CCS Northeastern machines, OO=/course/com3360 On the WWW, OO = http://www.ccs.neu.edu/research/demeter/course ========= Use the following header for your written homework submissions and put it at the top of the first page: Course number: COM 3360/NTU SE737 HW number Name: Account name: Assignment number: Date: Send your solution by email to the teaching assistant (kate) with subject line: Subject: COM3360/NTU SE737 HW number where number is the homework number. ========== Put the solutions to this homework into directory /proj/adaptive3/projects/com3360-f95/YOUR_LOGIN/hw5 ========== When you have questions about concepts and tools, please check first URL: ftp://ftp.ccs.neu.edu/pub/people/lieber/faq/Demeter-FAQ for an answer. Whenever you have questions about course material, please send e-mail to: mail lieberherr@ccs.neu.edu ccs.courses.com3360@ccs.neu.edu =============================================================== Theme: Evolution of Adaptive Object-Oriented Software Tcl/Tk PART A: =============================================================== Do assignment 5 in the Demeter book (page 558) with the following modification for Part 2: Instead of printing the list of class definitions, print the list of all concrete subclasses of the given class. For the example on page 559, the concrete subclasses of Expression are: Variable, Numerical, Compound. The concrete subclass of Compound is only Compound. Write your propagation patterns without using *bypassing*. What to turn is described in the Demeter book. PART B: =============================================================== Process your directory from PART A with isthmus-cd and isthmus-pp for class dictionary DH-small. Add to main.tcl (copied from main.tcl.sample) code for creating a button object with text "concrete subclasses" so that each time the button is clicked by the mouse, the propagation pattern from PART A is executed on the object in file: demeter-input. The output goes into a message widget each time the button is clicked. Turn in your modified main.tcl. Note that you can develop the modifications to main.tcl interactively by first typing them directly into the window where you run "run". Reminder: how to use Isthmus: demeter isthmus-cd cp Imakefile.sample Imakefile gen-make cp main_tcl.C.sample main.C cp main.tcl.sample main.tcl isthmus-pp *.pp ======================================================= PART C: ======= Integrating your own C++ code with a Demeter generated environment. =================================================================== In this part you learn about: - Developing your own C++ class library and using it with a Demeter generated C++ class library. This shows you how two C++ class libraries can communicate. - Working with objects which contain objects as opposed to pointers to objects. Let's assume that you have a C++ application which you would like to make more maintainable. One good strategy is to rewrite your software incrementally as adaptive software. To do this you need to be able to call your code from Demeter code and vice versa. Below we show how adaptive software can call your existing C++ application. You need to do the following steps: 1. You create a library from your C++ software. I have created such a library in $OO/hw/5/external-lib/ext You use a Makefile to compile your library and to create a *.a file. Such a Makefile is in the above directory. 2. Use of the libraries in a Demeter generated C++ class library. I have created such a library in $OO/hw/5/external-lib/generated I refer to this directory as HW7. 2.1 class dictionary You refer to external class C with C@@LIB. LIB can be any identifier which is irrelevant. You can use an external class as a part: A = C@@LIB. or you may inherit from it: NewC = NewPart *inherit* C@@LIB. For an example, see HW7/cd.cd Example= // reuse through part-of relationship Automobile@@LIB // reuse through inheritance MyAutomobile . MyAutomobile = DemNumber *inherit* Automobile@@LIB. List(S) ~ {S}. 2.2 Imakefile A complete example is in HW7/Imakefile You update INCLUDES to indicate where the header files are for your application. You update LOCAL_LIBRARIES to indicate where the library file of the form *.a can be found for your application. You also update NOCONSTRUCTOR to indicate for which classes you don't want to have a constructor generated. For example, if for class NewC you don't want a constructor, you set NOCONSTRUCTOR = NewC For all classes which inherit from an external class (i.e. a class in your application) you don't want Demeter to generate a constructor. Instead you want to write your own which calls the constructor of the super class explicitly. 2.3 Constructors You write a separate *.C file which contains the constructors. It is important that the constructor you write is a default constructor, i.e., all arguments must have a default value. You write a comment line to define the default values, using the Demeter notation used by the headers command. An example of a constructor definition is in HW7/MyAutomobile-constr.C Complete Example: in HW7/../ext: Existing C++ code: we assume two files: auto.h and auto.C // --------------------------------------- auto.h #include #include class Motor { public: Motor(int cost_in) {cost = cost_in;} int cost;}; class Transmission { public: Transmission(int cost_in) {cost = cost_in;} int cost;}; class Automobile { public: Automobile(int motor_cost, int transmission_cost) UNKNOWN1 UNKNOWN2(UNKNOWN3), UNKNOWN4(UNKNOWN5){}; Motor m; Transmission t; int computeCost();}; // ---------------------------------------- auto.C #include "auto.h" int Automobile::computeCost(){ return (UNKNOWN6 + UNKNOWN7);} // ----------------------------------------- Makefile to create library .SUFFIXES: .o .C .c SRC = auto.C OBJ = $(SRC:.C=.o) CFLAGS = .C.o: CC $(CFLAGS) -c $*.C libauto.a: $(OBJ) rm -f $@ ar cr $@ $(OBJ) ranlib $@ clean: rm -f libauto.a *.o auto.o: auto.h // -----------------in Demeter generated environment // --------------------------------------------- cd.cd Example= // reuse through part-of relationship Automobile@@LIB // reuse through inheritance MyAutomobile . MyAutomobile = DemNumber *inherit* Automobile@@LIB. List(S) ~ {S}. // ----------------------------------------------------- Imakefile // changes only // FOR UNKNOWN8 and 9 GIVE THE FULL PATH OF YOUR DIRECTORY. INCLUDES = -I$(DEMETER)/include -I/UNKNOWN8/ext LOCAL_LIBRARIES = \ /UNKNOWN9/ext/libauto.a \ $(DEMETER)/lib-$(SIMI)/`get-cpu`/libdemeter`basename $(CCC)`.a -ll NOCONSTRUCTOR= MyAutomobile // -------------------------------------- constructor MyAutomobile #include "UNKNOWN.h" // see User's Guide 5.2 //++ defaults (DemNumber* mileage_in = NULL, int motor_cost = 0, int transmission_cost = 0) MyAutomobile::MyAutomobile( DemNumber* mileage_in, int motor_cost, int transmission_cost) UNKNOWN10 Automobile(UNKNOWN11, transmission_cost){ mileage = mileage_in;}; // ------------------------------------------- include to main.C // ------------------------------------------- user-calls.h iExample -> set_a(new Automobile(UNKNOWN12, 30)); iExample -> set_ma(new MyAutomobile(new DemNumber(30), 2, 3)); cout << "first car cost " << iExample->get_a() -> computeCost() << endl; cout << "second car cost " << iExample->get_ma() -> computeCost() << endl; iExample -> g_displayAsTree(); iExample -> set_ma(new MyAutomobile(new DemNumber(50))); cout << "second car cost " << iExample->get_ma() -> computeCost() << endl; iExample -> g_displayAsTree(); // ------------------------------------------ output Parsing in object in: demeter-input. Displaying the copied object as a tree: : Example ( < ma > : MyAutomobile ( < mileage > : DemNumber "25" ) ) End of display. first car cost 50 second car cost 5 : Example ( < ma > : MyAutomobile ( < mileage > : DemNumber "30" ) ) second car cost 0 : Example ( < ma > : MyAutomobile ( < mileage > : DemNumber "50" ) ) // produced from demeter-input containing "25" Your task is to find and turn in the unknowns in the programs HW7/user-calls.h HW7/MyAutomobile-constr.C HW7/../ext/auto.h HW7/../ext/auto.C so that the run command in HW7 produces the above output. There are 12 unknowns UNKNOWN1, ... ,UNKNOWN12 to be found. Run your program to make sure you have the correct answer. Some hints: 1. Parts which use @@LIB are ignored by the generic software. 2. Use man headers to learn more about controlling the generation of the header files. 3. Read chapter 5 of the User's Guide to learn more about the Imakefile and linking to external libraries. 4. Read in your C++ book about passing arguments to the constructor of a super class. This is called Base Class Initialization. The member initialization list is used to pass arguments to a base class constructor. For example: Bear::Bear( char* name) // : base-class-name(args) : ZooAnimal(name) { // set immediate data members of Bear } 5. Read in your C++ book about objects which contain real objects as opposed to pointers to objects. Learn the syntax for calling member functions of such objects. 6. Read in your C++ book about member class objects. What is the order of constructor invocation? How can you pass arguments to the member class constructor? Example: Word::Word(char* s, int count) : name(s) { occurs = cnt; } class Word { ... private: int occurs; String name; }; ======================================================= PART D: ============================================================== Choose a project for the rest of the course. More information is forthcoming. ================================================================== For your convenience, the four class dictionaries needed for PART A are listed below. //------------------ // DH-small CdGraph = List(Adjacency). Adjacency = Vertex Neighbors. Neighbors : C | A *common* List(Vertex). A = ":" List(Vertex). C = "=". Vertex = DemIdent. List(S) ~ "(" {S} ")". //------------------ // DH-nice // class dictionary Cd_graph = Adj Adj_list. Adj = Vertex Neighbors ".". Neighbors: Construct | Alternat. Construct = "=" Any_vertex_list. Alternat = ":" Vertex "|" Vertex. Any_vertex : Labeled_vertex | Syntax_vertex. Syntax_vertex = DemString. Labeled_vertex = "<" DemIdent ">" Vertex. Adj_list: Empty_cd_graph | Cd_graph. Any_vertex_list: Empty | Nany_vertex_list. Nany_vertex_list = Any_vertex Any_vertex_list. Empty = . Empty_cd_graph = . Vertex = DemIdent. //DH-full //-------------------- // Copyright (C) 1991 Northeastern University. // Permission is granted to any individual or institution to use, copy, modify, // and distribute this class dictionary, provided that this complete copyright // and permission notice is maintained, intact, in all copies and supporting // documentation. Cd_graph = < adjacencies > Nlist(Adjacency) . Adjacency = < source > Vertex ["(" < parameters> Comma_list(Vertex) ")"] < ns > Neighbors "." . Neighbors : Neighbors_wc | Repetit_n *common*. Neighbors_wc : Construct_ns | Alternat_ns *common* < construct_ns > List(Any_vertex). Construct_ns = "=". Alternat_ns = ":" < alternat_ns > Bar_list(Term) [ Common]. Common = "*common*". Repetit_n = "~" Sandwich(Kernel). Kernel = [ Term ] "{" Sandwich(Term) "}". Any_vertex : Opt_labeled_term | Optional_term | Syntax_vertex . Vertex = < vertex_name > DemIdent. Syntax_vertex : Regular_syntax | Print_command *common*. Print_command : Print_indent | Print_unindent | Print_skip | Print_space *common*. Print_indent = "+" . Print_unindent = "-" . Print_skip = "*l" . Print_space = "*s" . Regular_syntax = < string > DemString . Opt_labeled_term : Labeled | Regular *common* Term. Regular = . Labeled = "<" < label_name > DemIdent ">" . Term : Normal *common* Vertex ["@" Module_name] ["(" Comma_list(Term) ")" ] . Module_name = DemIdent. Normal = . Optional_term = "[" Sandwich(Opt_labeled_term) "]". // parameterized classes List(S) ~ {S}. Nlist(S) ~ S {S}. Bar_list(S) ~ S {"|" S}. Comma_list(S) ~ S {"," S}. Sandwich(S) = List(Syntax_vertex) S List(Syntax_vertex) . //-------------------- //DH-ancient Start = Grammar. Grammar ~ {Rule}. Rule = DemIdent Body ".". Body : Construct | Alternat | Repetit. Construct = "=" List(AnySymbol). Alternat = ":" BarList(DemIdent). SandwichedSymbol = AuxList Symbol AuxList. Repetit = "~" AuxList [ DemIdent ] "{" SandwichedSymbol "}" AuxList. AnySymbol : Symbol | OptSymbol | Aux. Symbol = [ "<" DemIdent ">" ] DemIdent. OptSymbol = "[" SandwichedSymbol "]". Aux : Syntax. Syntax = DemString. AuxList ~ { Aux }. List(S) ~ {S}. BarList(S) ~ S { "|" S}. ==========================================================================