We are taking an incremental approach to software development in this course: In hw 1 you read and analyzed Java programs, in hw 2 you filled in missing information in Java programs that use DJ, in hw 3 you modified programs that use class dictionaries (similar to XML schemas) and a tiny bit of DemeterJ (the weaving feature offered by Class1 { {{ ... }} } Class2 { {{ ... }} } ... ).
Now in hw 4 you write from scratch a simple Java program using DJ and a tiny bit of DemeterJ (the weaving feature) but you are given the class dictionary.
This homework has two parts: The first part is the Laboratory Guide and the second part is a simple UNIX shell. The Laboratory Guide introduces you to DemeterJ (formerly called Demeter/Java) but most of what you learn will help you to write Java Programs with DJ and a tiny bit of DemeterJ. So when you go through the Laboratory Guide, focus on class dictionaries and how you would express the adaptive programs you encounter directly using DJ without using the adaptive programming language of DemeterJ.
Name substitution throughout Laboratory Guide and other documents: Demeter/Java -> DemeterJ demjava -> demeterj Please note that homework submission is electronic to black board and hardcopy submission. Follow the submission format from earlier homeworks! This will allow the teaching assistant to run your programs and mark your printed copies. Please package up your whole directory, but without any .class or .java files. The teaching assistant will be generating them from the DemeterJ files.
The class dictionary for DemeterJ which defines the DemeterJ notation. It is reachable from the DemeterJ and AP-Studio resources page: http://www.ccs.neu.edu/research/demeter/DemeterJava/
Plus additional reading as described below.
PURPOSE: See DemeterJ in action. Study an application of the concepts covered so far in the context of a Java application.
Tasks to be done: Read and work through the Laboratory Guide using DemeterJ and hand in all files modified.
Browse through the DemeterJ User's Guide available from the DemeterJ and AP-Studio Resources page http://www.ccs.neu.edu/research/demeter/DemeterJava/. Focus on class dictionaries and only a little bit on the adaptive programming language of DemeterJ.
Browsing the User's Guide will help you to better understand the Laboratory Guide available from the same resource page.
The purpose of this laboratory exercise is to see adaptive programming in operation in the Java world. Turn in all the files you modified.
Please send mail to csu670-grader@ccs.neu.edu if you find something not clear in the Laboratory Guide.
From a happy user of the Demeter/C++ lab guide. The DemeterJ Laboratory Guide is a translation of the Demeter/C++ Lab Guide.
Hi Crista: I just finished working through the Demeter Lab Guide and already feel a lot more comfortable with Demeter. The Lab Guide is concise, clear and written with a great deal of empathy for the user. Congratulations for doing such an excellent job with the Lab Guide! ...
We simulate a few Operating System file management commands by building our own data structures that represent what the commands do. You are not allowed to use Runtime and Process objects in this homework. Your program should be able to handle inputs like:
mkdir a mkdir b cd a mkdir c mkdir d cd d mkdir x cd .. cp -r d e cd .. echo "before du" du find . -name x -printand produce the same output as UNIX, except that the disk usage command "du" prints only the file structure and no sizes. More precisely, your program should be able to execute a list of commands as defined by the Extended Backus-Naur-Form (EBNF) grammar below (in Demeter class dictionary notation):
The full cd is also here: Full cd in file os.cd. FileSystem = CompoundFile EOF. File : SimpleFile | CompoundFile common < f > FileName. SimpleFile = "simple". CompoundFile = "compound" < contents > PList(File). Commands = List(Command) EOF. Command : Simple. Simple : MakeDirectory | ChangeDirectoryUp | ChangeDirectoryDown | RecursiveCopy | DiskUsage | Find | Echo | SymbolicLink | RemoveDirectory | CreateEmptyFile | RemoveFile. MakeDirectory = "mkdir" DirectoryName. ChangeDirectoryUp = "cd ..". ChangeDirectoryDown = "cd" DirectoryName. RecursiveCopy = "cp -r" < source > DirectoryName < target > DirectoryName. DiskUsage = "du .". SymbolicLink = "ln -s" < from > FileName < to > FileName. RemoveDirectory = "rmdir" DirectoryName. // "touch f" creates an empty file called f. CreateEmptyFile = "touch" FileName. RemoveFile = "rm" FileName. Find = "find . -name" DirectoryName "-print". Echo = "echo" Message. FileName = Ident. DirectoryName = Ident. Message = String. PList(S) ~ "(" {S} ")". List(S) ~ {S}. Main = .For the input
mkdir a mkdir b cd a mkdir c mkdir d cd d mkdir x cd .. cp -r d e cd .. echo "before du" du find . -name x -printyour program should produce an output similar to:
before du ./a/c ./a/d/x ./a/d ./a/e/x ./a/e ./a ./b ./ . ./a/d/x ./a/e/xIt is important to do this part in stages. You get full credit if your program works correctly for the sublanguage that includes the commands
Simple = MakeDirectory | ChangeDirectoryUp | ChangeDirectoryDown | DiskUsage | RecursiveCopy | Find | CreateEmptyFile.You get a 10% extra point credit for this homework if you implement the full language. It is recommended that you start with primitive commands like CreateEmptyFile, MakeDirectory, ChangeDirectoryUp, ChangeDirectoryDown. Hint: Try to use the CopyVisitor of DemeterJ to do the copying:
CompoundFile{ traversal toAll(UniversalVisitor) { to *;} public CompoundFile copy() {{ CopyVisitor cv = new CopyVisitor(CompoundFile.class); this.toAll(cv); return (CompoundFile) cv.get_return_val(); }} }Another example: for the input
mkdir a mkdir b cd a mkdir c mkdir d cd .. duyour program should produce the output:
./a/c ./a/d ./a ./bBut you should write your program in such a way that it would be easy to add the rest of the commands. Note that RecursiveCopy, DiskUsage and Find have significant common behavior that you should factor out.
You should focus your efforts on correct inputs as described by the above grammar. It is not important that you give a good error message in case of a syntax error. But your program needs to handle correct inputs correctly.
To represent your file system you may want to use Java classes similar to the ones described below.
FileSystem =CompoundFile EOF. File : SimpleFile | CompoundFile common FileName. SimpleFile = "simple". CompoundFile = "compound" PList(File).
Solution approach: Use the data-binding approach of DemeterJ to generate Java class definitions and parser and pretty printer from a schema (class dictionary).
Start with the DemeterJ program in $SD/hw/4/os-phase1-better and add more behavior files to the program. For illustration purposes, I constructed a FileSystem-object manually and I printed it out with the display method.
A { {{ // in plain Java: // any additional instance variables // any additional methods }} } B { {{ // in plain Java: // any additional instance variables // any additional methods }} } // etc.In the Java methods you use DJ to program adaptively. Note that if a method needs additional instance variables, you may introduce them in your behavior file as shown above. This does not allow you to parse or print those variables. If you need that capability (which is rare), you need to introduce your instance variables in your .cd file.
This part is about capturing edge traversals. For the traversal: "from Commands to FileName" started on a Commands-object, we want to print the names of the classes of objects that are traversed and that have an outgoing edge to a FileName-object.
The program in os-phase1-better approximates what we want but it prints too much:
object visited Commands command_list Command_List object visited Command_List first Nonempty_Command_List object visited Nonempty_Command_List it CreateEmptyFile object visited CreateEmptyFile filename FileName object visited Nonempty_Command_List next Nonempty_Command_List object visited Nonempty_Command_List it CreateEmptyFile object visited CreateEmptyFile filename FileName object visited Nonempty_Command_List next Nonempty_Command_List object visited Nonempty_Command_List it MakeDirectory object visited Nonempty_Command_List next Nonempty_Command_List object visited Nonempty_Command_List it MakeDirectory object visited Nonempty_Command_List next Nonempty_Command_List object visited Nonempty_Command_List it ChangeDirectoryDown object visited Nonempty_Command_List next Nonempty_Command_List object visited Nonempty_Command_List it MakeDirectory object visited Nonempty_Command_List next Nonempty_Command_List object visited Nonempty_Command_List it MakeDirectory object visited Nonempty_Command_List next Nonempty_Command_List object visited Nonempty_Command_List it CreateEmptyFile object visited CreateEmptyFile filename FileName object visited Nonempty_Command_List next Nonempty_Command_List object visited Nonempty_Command_List it RecursiveCopy object visited RecursiveCopy source FileName object visited RecursiveCopy target FileName object visited Nonempty_Command_List next Nonempty_Command_List object visited Nonempty_Command_List it ChangeDirectoryUp object visited Nonempty_Command_List next Nonempty_Command_List object visited Nonempty_Command_List it Echo object visited Nonempty_Command_List next Nonempty_Command_List object visited Nonempty_Command_List it DiskUsage object visited Nonempty_Command_List next Nonempty_Command_List object visited Nonempty_Command_List it CreateEmptyFile object visited CreateEmptyFile filename FileName object visited Nonempty_Command_List next Nonempty_Command_List object visited Nonempty_Command_List it Find object visited Nonempty_Command_List next Nonempty_Command_List object visited Nonempty_Command_List it CreateEmptyFile object visited CreateEmptyFile filename FileNameIt prints too much because it should only print lines like:
object visited CreateEmptyFile filename FileName object visited CreateEmptyFile filename FileName ..The above output is produced by:
// File incomingToFileName.beh // print all objects that have one or more FileName parts // and that are visited during the traversal Commands { {{ void incomingToFileName(TraversalGraph where) { FileNameVisitor cV = new FileNameVisitor(); where.traverse(this, cV); } }} } FileNameVisitor { {{ void before(Object source, String s, Object target) { System.out.println(" object visited " + source.getClass().getName() + " " + s + " " + target.getClass().getName()); } }} }You need to modify this program so that it prints only the lines where the target object is a FileName-object. You are not allowed to use any explicit conditional statements. The documentation for this capability is a little hidden in the DJ API. Study method "invokeMethods" in the Visitor class. "n" is either "before" or "after".
Consider the following design task: Given a relation over domain {0,1} of at most rank 3, determine the variables that are forced. For example, Or(x) forces x to 1. if x=0 the relation is guaranteed to be unsatisfied.
The relation given by the truth table: (nothing means 0) xyz 000 001 010 1 100 011 101 110 1 111 forces y=1 and z=0. E.g., if y=0, the relation is guaranteed to be unsatisfied. xyz 000 1 001 010 1 100 011 101 110 1 111 forces z=0.Design a function forced: int forced(int relationNumber, int variablePosition) which returns 0, 1 or -1. -1 means that the variable at variablePosition is not forced. 0 or 1 means that the variable at variablePosition is forced to 0 or 1, respectively.