(Data Structure and Programming) Homework #3

$35.00

Category: You will Instantly receive a download link for .zip solution file upon Payment || To Order Original Work Click Custom Order?

Description

5/5 - (5 votes)

1. Problem Description In this homework, we are going to design a more complete user interface (on top of Homework #2) for a simple command-line database system (somewhat similar to Homework #1). The generated executable is called “mydb” and has the following usage: mydb [-File ] where the bold words indicate the command name or required entries, square brackets “[ ]” indicate optional arguments, and angle brackets “< >” indicate required arguments. Do not type the square or angle brackets. This simple command-line database system should provide the following functionalities: 1. Create DB by reading in data from a .json (JSON) file. Please refer to Homework #1 for the simplified JSON format. However, we further limit the format of the “key” to a string starting with either English letters (i.e. a-z, AZ) or underline symbol (i.e. ‘_’). (See command “DBAPpend” for more detailed description) 2 2. Add a new JSON element to the end of the JSON object. 3. Print out the JSON object or a JSON element in the JSON object by specifying a “key” string. 4. Sort the JSON elements by either “key” or “value” in ascending order. 5. Report the number of JSON elements in the JSON object. 6. Compute the summation and average of the JSON elements by their “values”. 7. Report the maximum and minimum JSON element by comparing the “values”. 8. Use “cout” to print the correct outputs and “cerrr” to print out the erroneous message. 2. Supported Commands The supported commands of “mydb” include: DBAPpend: append a JSON element (key-value pair(s)) to the end of DB DBAVerage: compute the average of the DB DBCount: report the number of JSON elements in the DB DBMAx: report the maximum JSON element DBMIn: report the minimum JSON element DBPrint: print the JSON element(s) in the DB DBRead: read data from .csv file DBSOrt: sort the JSON object by key or value DBSUm: compute the summation of the DB DOfile: execute the commands in the dofile HELp: print this help message HIStory: print command history Quit: quit the execution The lexicographic notations in this section are summarized in the following table: CAPITAL LETTERS or leading ‘-‘ The leading ‘-‘ and capital letters in the command name or parameters are mandatory entries and will be compared “caseinsensitively”. The following letters can be partially skipped. However, when entered, they should match the specification “case-insensitively”. For example, for the command “DOfile” — l do (ok) 3 l dofile (ok) l DoF (ok) l d (not ok; at least “do”) l dofill (not ok; not match) l dofile1 (not ok; extra letter) Round bracket “()” Meaning it should be replaced by a proper argument as suggested by the “(type variable)” description in the round brackets. For example, the parameter in “HIStory [(int nPrint)]” should be replaced by an integer which is the number of histories to print. Angle brackets “<>” Mandatory parameters; they should appear in the same relative order as specified in the command usage. Square brackets “[]” Optional parameters; they can appear anywhere in the command parameters. Dot dot dot “…” Repeatable arguments; meaning the followed argument can be repeated multiple times. Or ‘|’ Or condition; either one of the argument will do. Please note that the “[ ]” optional parameters can appear anywhere in the command line, while the “< >” mandatory parameters must follow the relative order as specified in the command usage. For example, if the command “test” has the following usage — Usage: TEST [op3] [op4] The following are legal: > test op1 op2 // op3 or op4 can be omitted > test op4 op1 op3 op2 // op3 op4 order is not enforced > test op3 op1 op2 But the following are illegal: > test op2 op1 // op1 op2 order is enforced > test op1 op3 op4 // op1 and op2 are mandatory For the following command, use “cerr” (instead of “cout”) to print out the error message. 2.1 Command “DBAPpend” Usage: DBAPpend <(string key)><(int value)> 4 Description: Append an JSON element (i.e. key-value pair) to the end of the DB. The options <(string key)><(int value)> must present. If any of the arguments is missing, print out an error. “key” is composed of English letters (i.e. a-z, A-Z), digits (i.e. 0-9), and underline symbol (i.e. ‘_’). The first character of the “key” must be an English letter or underline symbol. Use “isValidVarName(const string&)” in “util/myString.cpp” to check the validity of the “key”. If any error occurs, or if there already exists a JSON element with the same key (no matter the specified value is the same or not), print out an error. “value” must be a valid integer. Otherwise, print out an error. No message is printed on the success of insertion. Note that the added element affects the JSON object in your program only. It will not change (i.e. write back to) the read-in file. If the JSON file hasn’t been read in, print out an error message “Error: DB is not created yet!!”. Example: mydb> DBAPpend Mary 30 mydb> DBAPpend KK 4 // Assume { “KK” : 4 } already exists Error: Element with key “KK” already exists!! mydb> dbAPpend Error: Missing option!! mydb> dbAPpend ric2k1 Error: Missing option!! mydb> DBAPpend Mary ric2k1 // Any of the error message is OK Error: Missing option after “Mary”!! Error: Illegal option!! (ric2k1) 2.2 Command “DBAVerage” Usage: DBAVerage Description: Print out the average of the values in the DB. Use “fixed” and “setprecision(2)” for cout to control the output precision. If the DB is empty, report NAN (a float const number, #include ) as an error. Example: mydb> DBAVe The average of the DB is 13.38. mydb> DBAVe Error: The average of the DB is nan. 5 2.3 Command “DBCount” Usage: DBCount Description: Print out the number of JSON element(s) in the DB. Be noted on the singular and plural forms of “element(s)”. Example: mydb> DBCount There are 57 JSON elements in DB. mydb> DBCount There is 1 JSON element in DB. mydb> DBCount There is no JSON element in DB. 2.4 Command “DBMAx” Usage: DBMAx Description: Print out the maximum JSON element (i.e. with the maximum value) in the DB. If there are multiple elements with the same maximum value, print out either one (preferably, the first one encountered). If the DB is empty, report NAN (a float const number, #include ) as an error. Example: mydb> DBMAx The max JSON element is { “Mary” : 100 }. mydb> DBMAx Error: The max JSON element is nan. 2.5 Command “DBMIn” Usage: DBMIn Description: Print out the minimum JSON element (i.e. with the minimum value) in the DB. If there are multiple elements with the same minimum value, print out either one (preferably, the first one encountered). If the DB is empty, report NAN (a float const number, #include ) as an error. Example: mydb> DBMIn The min JSON element is { “John” : -87 }. mydb> DBMIn Error: The min JSON element is nan. 6 2.6 Command “DBPrint” Usage: DBPrint [(string key)] Description: Print out the JSON DB. If the option “key” is NOT specified, print out the entire JSON object. On the other hand, if the option “key” is specified, print out the JSON element with the the “key” (i.e. performing case-sensitive comparison). If not found, print out an error. The printing format is as shown in the example. If the JSON file hasn’t been read in, print out an error message “Error: DB is not created yet!!”. Example: mydb> DBPrint { “Ric” : 100, “John” : 50 } Total JSON elements: 2 mydb> DBPrint Ric { “Ric” : 100 } mydb> DBPrint ric Error: No JSON element with key “ric” is found. 2.7 Command “DBRead” Usage: DBRead <(string jsonFile)> [-Replace] Description: Read the data from “jsonFile” to the database (DB). If file “jsonFile” doesn’t exist, print out an error message. If the DB already exists and the option “-Replace” is not specified, issue an error. If the option “- Replace” is given, replace the DB content with the data in the “jsonFile”. Example: mydb> DBRead test1.json // assume test1.json doesn’t exist Error: “test1.json” does not exist!! mydb> DBRead test2.json // assume DB already exists Error: DB exists. Use “-Replace” option for replacement. mydb> DBRead test3.json -rep DB is replaced… “test3.json” was read in successfully. 2.8 Command “DBSOrt” Usage: DBSOrt <-Key | -Value> 7 Description: Sort the JSON elements with key (-Key) or value (-Value) in ascending order. No output message is needed for this command, even if the JSON object is empty. Example: mydb> DBSOrt Error: Missing option!! mydb> DBSOrt -Key mydb> DBSOrt -Value 2.9 Command “DBSUm” Usage: DBSUm Description: Print out the summation of the values of the JSON elements in the DB. If the DB is empty, report NAN (a float const number, #include ) as an error. Example: mydb> DBSUm The sum of the DB is 2880. mydb> DBSUm Error: The sum of the DB is nan. 2.10 Command “DOfile” Usage: DOfile <(string filename)> Description: Execute the commands in the dofile. After the execution, it should go back to the command prompt. Example: mydb> dofile dofile1 2.11 Command “HELp” Usage: HELp [(string cmd)] Description: Print out help message. If command is specified, print out its usage. Otherwise, print out the list of all commands with simple descriptions. Examples: mydb> help mydb> help dofile mydb> help do 2.12 Command “HIStory” Usage: HIStory [(int nPrint)] 8 Description: Print command history. The argument specifies the upper bound of how many of the last command history entries it will print. If not specified, all the histories will be printed. Example: mydb> history 8 2.13 Command “Quit” Usage: Quit [-Force] Description: Quit the execution. Prompt a confirmation if the argument “-Force” is not present. Examples: mydb> quit mydb> q –f 3. Implementation 3.1 File/Directory Structure After decompressing the .tgz file, you should see the following files and directories: hw3> ls -aF Homework_3.docx Homework_3.pdf Makefile MustExist.txt MustRemove.txt bin/ dofiles/ include/ lib/ mydb@ ref/ src/ testdb@ tests/ “bin/” and “lib/” are the directories to store the binary (executable) and library files, respectively. “Makefile” is the top-level makefile. You only need to type “make” in this root directory and it will go to different source code directories to invoke other makefiles, check the file dependency, compile the source codes, create libraries and final executable, and return. The generated executable will be stored in “bin/” and a symbolic link “mydb” will be created in this directory for the easy access of the executable. “testdb” is another executable/symbolic link for testing your DB operations. Please see Section 4 for details. “dofiles/” contains some dofiles for you to test, and “ref/” includes the reference executables for linux and mac platforms. Please play with them to understand the spec of the commands in this homework. “tests/” directory contains some .json files for you to test. The directory “include/” contains the symbolic links of the header files (.h) to be shared within different source code packages. The “src/” contains the source codes of different packages, each defined in a sub-directory. In this homework, the packages under “src/” include: 9 hw3> ls src cmd/ db/ main/ Makefile.in Makefile.lib test/ util/ The “main/” directory, as its name suggests, contains the main() function of the entire program. “cmd/” implements the utilities of the command interface. It also defines some common commands such as “help”, “quit”, “history”, etc. The “db/” directory is for the simple command-line database manager. The common utilities, such as customized string functions, memory management, container classes, etc, should be placed under the “util/” directory. You should try to take advantages of these common utility functions. The “test/” directory is to test your “db/” implementation before completing the command interface. Please see Section 4 “What you should do?” for further guidance. 3.2 Class description 1. Classes about command registration: class CmdParser, class CmdExec and its derived classes In this program, commands in different packages (i.e. different source code directories) are “registered” through the CmdParser command manager. There is one global variable cmdMgr and commands are added through its regCmd() member function. For example, in file “cmdCommon.cpp”: bool initCommonCmd() { if (!(cmdMgr->regCmd(“Quit”, 1, new QuitCmd) && cmdMgr->regCmd(“HIStory”,3,new HistoryCmd)&& cmdMgr->regCmd(“HELp”, 3, new HelpCmd) && cmdMgr->regCmd(“DOfile”, 2, new DofileCmd) )) { cerr << “Registering \”init\” commands fails…” << ” exiting” << endl; return false; } return true; } Four commands (quit, history, help, dofile) are registered to the cmdMgr. The first parameter of the CmdParser::regCmd() function specifies the name of the command. Please note that the leading capital characters (e.g. HIS in HIStory) are mandatory matching. They are made capital for conventional reason. The second parameter specifies the number of the mandatory matching characters. The last parameter is a functional object that inherits the class CmdExec. 10 The class CmdExec is the common command registration and execution interface. To create a new command, you need to declare a derived class such as class QuitCmd which defines at least the following three member functions: (1) exec(): parse the command option(s) and execute the command, (2) usage(): print out the command usage, and (3) help(): print out the command definition for the HELp command. For more details, please refer to functions CmdParser::regCmd(), CmdParser::execOneCmd() in file “cmdParser.cpp”, and exec/usage/help() members functions of each derived class such as in file “cmdCommon.{h,cpp}”. For the sake of convenience, we define a MACRO CmdClass(T) in the file “cmdParser.h” so that we can easily declare an inherited class of CmdExec as: CmdClass(HelpCmd); Please refer to the file “cmdCommon.cpp” for more examples. 2. Classes about keyboard mapping: class CmdParser and enum ParseChar The class CmdParser defines the functions to process inputs from the standard (cin) and file inputs, and the enum ParseChar is to define the keyboard mapping. Please note that the grading of this homework will not include special keys such as “delete”, “backspace” and arrow keys, etc. So you can actually ignore them. (i.e. Don’t worry about the keyboard mapping) We will focus on testing the command registration and database’s functionalities. In fact, in “src/Makefile.in” we actually define the flag “TA_KB_SETTING” in the macro CFLAGS and thus we will use our keyboard mapping by default. However, if you want to customize your keyboard mapping, please change the “#ifndef” part of the “#ifndef TA_KB_SETTING” in files “cmdParser.h”, “cmdCharDef.cpp” and undefine “TA_KB_SETTING” in the macro CFLAGS of “src/Makefile.in”. 3. Classes about database manager: The classes and member functions for JSON element and object are defined in files “dbJson.{h,cpp}”. The class DBJson defines all the interfaces to manipulate the JSON object, and its data member “vector _obj” stores the JSON elements. The class DBJsonElem represents the JSON element, and the struct DBSortKey and DBSortValue are used as StrictWeakOrdering functional objects for the STL sort() algorithm. 3.3 How is a command string stored in _cmdMap? When a command is registered in the CmdParser::cmdReg() function, the command string is partitioned into two parts: the former mandatory part (e.g. “HEL” in “HELp” command) will be converted to all-capital and used as the key to store the command in CmdParser::_cmdMap. Note that the characters are made all capital in order to facilitate the case-insensitive comparison. The second template argument of “map CmdParser::_cmdMap” is an inherited 11 pointer object of class CmdExec. For example, for the command “HELp”, a pointer object of the inherited class HelpCmd will be created and stored. The latter optional part of the command string (e.g. “p” in “HELp” command) will be stored as a private data member “string _optCmd” of the corresponding class object. It will be checked when parsing the command line input. 3.4 Makefile There are 5 types of makefiles: 1. Top-level Makefile: for the entire program creation 2. “make.$pkgName” in each of the source code directories: calling “Makefile.in” and “Makefile.lib” to construct library for each source code package. In this file, the macro PKGFLAG is to define the compilation flags specific to this package, EXTHDRS defines the header files that should be exposed to other (external) packages (so they will be symbolically linked to the “include” directory), and EXTRAOBJS defines the extra object files that are not compiled from the .cpp files in this directory. 3. Makefile.in: common core for the makefiles in different source code directories — (i) define the compilation rules, (ii) create file dependencies, (iii) create symbolic links for the external header files from the source code directory to the “include” directory. 4. Makefile.lib: makefile to create libraries for each package. 5. “make.main” in the “main” source code directory: to perform linking and create the final executable. Before making the program, you are suggested to type “make linux18”, “make linux16” or “make mac” to configure the provided object file “cmdRead.o” for your environment. Type “make” for top-level Makefile to create the executable. Use “make clean” to remove all the objective files, libraries, etc. 3.5 Useful utility functions Please pay attention that there are many prewritten utility functions that you can take advantage of for your TODOs. For example, in class CmdExec, lexNoOption(), lexSingleOption() and lexOptions() can parse the command option into tokens. In file util/myString.cpp, the function myStrNCmp(const string& s1, const string& s2, unsigned n) performs case insensitive comparison between s1 and s2 for the first n characters, and check the compatibility for the rest. The function myStr2Int(const string& str, int& num) can convert the string “str” to integer “num”, and the function isValidVarName(const string& str) can check if the parameter “str” is a valid key for a JSON element. 12 3.6 Advanced Feature: “Tab” support When the “tab” key is pressed, all the partially matched commands will be listed. Depending on the cursor position, there can be several possible responses: 1. If nothing but space characters is before the cursor, pressing “tab” key will list all the commands. [Example] // Before pressing “tab” mydb> // After pressing “tab” DOfile HELp HIStory GNADD GNCOMPare GNMULTiply GNPrint GNSET GNSUBtract GNVARiable mydb> Note that each command above is printed by: cout << setw(12) << left << cmd; // cmd is a string And a new line is printed for every 5 commands. After printing, you should re-print the prompt and place the cursor back to its original location (including space characters). 2. If only partial command is matched, pressing “tab” should list all the possible matched commands. (multiple matches) [Example] // Before pressing “tab” mydb> h // After pressing “tab” HELp HIStory mydb> h 3. But if there is only one possible match, pressing tab should complete the command. A space character will also be inserted after the command to separate it from the trailing substring. The newly inserted characters should match the strings stored in CmdParser::_cmdMap and in “string _optCmd” of the corresponding inherited class object. [Example] // Before pressing “tab” mydb> hello world // After pressing “tab” mydb> heLp llo world 13 4. If no command can be matched, pressing “tab” will make a beep sound and the cursor will stay in the same location. [Example] // Before pressing “tab” mydb> hello world // After pressing “tab” mydb> hello world 5. If the string before the cursor has already matched a command, and if there is at least one space characters before the cursor, pressing “tab” for the first time will print out its command usage. [Example] // Before pressing “tab” mydb> hel lo world // After pressing “tab” Usage: HELp [(string cmd)] mydb> hel lo world After printing, the cursor should remain in the original location. 6. (Continued from 5) If the string before the cursor has already matched a command, and if there is at least one space characters before the cursor, pressing “tab” for the second time and onwards will list the file names in the current directory (Please refer to the function “listDir()” in “util/util.cpp”). Several possible cases as follow: (6.1) If the character before the cursor is a space ‘ ‘, there are several possibilities as follows: [Example] (applied to 6.1.1 ~ 6.1.3) // Before pressing “tab” mydb> hel world (6.1.1) in this directory there are multiple files and they do not have a common prefix, // After pressing “tab” — print out ALL the file names under current directory. Homework_3.docx Homework_3.pdf Makefile MustExist.txt MustRemove.txt bin dofiles include lib mydb ref src testdb tests mydb> hel world Note that each filename above is printed by: cout << setw(16) << left << fileN; // fileN is a string 14 And a new line is printed for every 5 commands. (6.1.2) in this directory there are multiple files and all of them have a common prefix, // After pressing “tab” — auto insert the common prefix and make a beep sound ==> DO NOT print the matched files and do not re-print the command line // (e.g.) Try this in “ref” directory mydb> hel mydb-world (6.1.3) only one file in the current directory // After pressing “tab” — print out the single file name followed by a ‘ ‘ // (e.g.) Try this in “bin” directory mydb> hel mydb world // Note: if the “tab” is pressed again, make a beep sound and do not print the single file name again. (6.2) If the character before the cursor is NOT a space ‘ ‘, treat the substring before the cursor as a “prefix”. If there are multiple files under current directory that match the prefix, print out ALL the file names that match the prefix. [Example] // Before pressing “tab” mydb> hel McDonald // After pressing “tab” Makefile MustExist.txt MustRemove.txt mydb> hel McDonald (6.3) However, if in (6.2) the multiple matched file names have a common prefix, automatically insert the common prefix to the command line and make a beep sound. DO NOT print out the matched files and do not re-print the command line. [Example] // Before pressing “tab” mydb> hel MucDonald // After pressing “tab” mydb> hel MustcDonald // Note: if the “tab” is pressed again, it will match the case (6.2) and print out MustExist.txt and MustRemove.txt (6.4) In (6.2), if there is only ONE matched file, insert the remaining of the matched file name followed by a space ‘ ‘. 15 [Example] // Before pressing “tab” mydb> hel MustEcDonald // After pressing “tab” mydb> hel MustExist.txt cDonald // Note: if the “tab” is pressed again, make a beep sound and do not print the single file name again. (6.5) In (6.2), if there is NO matched file for the prefix, make a beep sound and leave the cursor in the original position. [Example] // Before pressing “tab” mydb> hel Yellow // After pressing “tab” mydb> hel Yellow 7. If the first word is not a match of a single command, and the cursor is not on the first word, pressing “tab” should make a beep sound and the cursor will stay in the same location. [Example] // Before pressing “tab” mydb> he llo world // After pressing “tab” mydb> he llo world Please note that this is an advanced feature. Do this only if you have completed all the other TODO’s. 3.7 Adding new source code directory (not required in this homework) 1. Under “src” directory, create a new subdirectory. Name the directory properly as the package name. 2. In the top-level makefile, add the package name (usually equal to the directory name) to the macro “LIBPKGS”. 3. In the new package directory, copy the “make.$packageName” from other source code directory and rename its suffix with the package name. Remove the assignment on the “EXTHDRS” variable if any. Add in header file name to the “EXTHDRS” later if you intend to share that header file with other packages. 16 4. What should you do? You are encouraged to follow the steps below for this homework assignment: 1. Read the specification carefully and make sure you understand the requirements. 2. Think first how you are going to write the program, supposed you don’t have the reference code… 3. Study the provided source code. Please be advised that the number of lines of the reference code is 2118. If you have never handled a software program in such a scale before, please read it “smartly”. You may want to first figure out the layout of files and directories, major data structure (i.e. classes), and how the functions are called starting from “main()”. Please don’t dig into detailed implementation in the beginning. Try to “guess” the meaning of the functions and variables, and have a “global” view of the program first. You can also use “ctags” to trace the codes. For more information about “ctags”, please refer to the third tip in Section 5. 4. What you should do in this homework assignment are commented with “TODO”’s. You should be able to complete this assignment by just finishing these todo’s. Roughly speaking, they contain 6 parts: (i) Complete the DJson and DBJsonElem classes (in DBJson.h and DBJson.cpp). Their functionalities are quite similar to Homework #1, but with some differences. Please read the descriptions carefully in Sections 1 and 2. (ii) You can test your DBJson and DBJsonElem implementation with the test program in the “test/” directory. Please refer to the main() function in test.cpp to add more testing codes. Simply type “make test” in the homework root directory to generate the test program “testdb”. Although testdb will not be included in the homework grading, you are encouraged to test more on your DBJson implementation before moving on to command interface. (iii) Finish the command interface in “cmdParser.cpp”. You need to know how to use STL “string”, “map” and “vector”. (iv) Implement the commands for “db” package (in dbCmd.cpp). You need to analyze the command line to see if there is any syntax error. Please note that there are several useful “string/char*” functions in files “util/myString.cpp” and “cmd/cmdParser.cpp”. Use them whenever applicable. In addition, you need to call the appropriate DBJson member functions for the DB manipulations. (v) Enhance the command “DOFile”. Please refer to the “TODO” in the source code “cmdCommon.cpp” for the supported features. You may need to add or modify member functions or data members of class CmdParser. However, please place the newly added data members to 17 the end of class CmdParser as the object file cmdReader.o is precompiled. If you insert data member in front of or in between existing data members, you may corrupt the relative memory addresses of the precompiled objects in cmdReader.o. For more information about how/what to add for command “DOFile”, please refer to the fourth and fifth tips in Section 5. (vi) Implement the “tab” function (i.e. CmdParser::listCmd() in “cmdParser.cpp”). 5. Complete your coding and compile it by “make”. Test your program frequently and thoroughly. Please note that we provide the complete code for the command line parser so that you don’t need to worry about the correctness and completeness of your Homework #2. However, we only provide the object file (i.e. cmdReader.o) so that it can be used for future homework assignment. Please note that the object file is platform dependent. Different platforms may require different compilations of object files. We provide three versions of cmdReader.o: (1) cmdReader.o.linux18 for Ubuntu 18 LTS linux machine, (2) cmdReader.o.linux16 for Ubuntu 16 LTS linux machine, and (3) cmdReader.o.mac for MAC. The file “cmdReader.o” is actually a symbolic link to one of them. The default is “cmdReader.o.linux18”. Please type “make linux18”, “make linux16” or “make mac” to switch between different platforms. 6. Reference programs mydb-linux18 / mydb-linux16 / mydb-mac (for the simple command-line JSON object manipulations) are available under the “ref/” directory. Please use them to compare your result. Please also watch out the announcements in the Ceiba website and FB group. 7. Rename the homework root directory to yourID_hw3 and type “make clean” to remove the executables and object files. Compress the directory by the command (on Linux or Mac Terminal): tar zcvf yourID_hw3.tgz yourID_hw3 Submit the .tgz file to Ceiba before deadline. 5. Some tips you should know 1. The provided reference code can be compiled even though the TODOs are not done. However, the produced executable cannot run (i.e. will crash). Please check the TODO’s and implement some of them first. 2. Sometimes you may encounter compilation error message like: make[1]: *** No rule to make target `../../include/util.h’, needed by `cmdCommon.o’. Stop. This is mainly because the hidden file “.extheader.mak” in some directory is accidentally removed. You can try to “make clean” and “make” again and usually it will resolve the problem. 18 3. Type “make ctags” to create ctages for all the source codes. Be sure to add in the following line in your “$HOME/.vimrc” (if you use “vim” and don’t have this file, create one): set tags=./tags,../tags Then when you use “vim” to edit the source code, you can jump to the function/class definition of the identifier your cursor is currently on by pressing “ctrl-]”. To come back, simply press “ctrl-t”. 4. The function closeDofile() is a TODO. However, how it is called is not included in the reference code. Here is the partial code of the function readCmd() in cmdReader.cpp . You can see how closeDofile() is called. bool CmdParser::readCmd(istream& istr) { resetBufAndPrintPrompt(); bool newCmd = false; while (!newCmd) { ParseChar pch = getChar(istr); if (pch == INPUT_END_KEY) { if (_dofile != 0) closeDofile(); break; } switch(ch) { … // Refer to the codes in homework #2 } } return newCmd; } 5. The handling of “ifstream* _dofile” for the “openDofile()” and “closeDofile()” may be trickier than you think. For example, if you need to open a dofile (i.e. the DOfile command) in a dofile, you need to store the original dofile and when the new dofile is finished, retrieve it and continue the execution from where you left. However, please note that you CANNOT “copy” fstream object. That’s why we declare _dofile as a pointer. 6. In “cmdReader.o”, there is a function “CmdParser::reprintCmd()” called by “CmdParser::listCommand()”, which is for the “tab” feature. Although you don’t have the cmdReader.cpp source code, you are free to call the function reprintCmd(): // Reprint the current command to a newline // cursor should be restored to the original location void CmdParser::reprintCmd() { 19 cout << endl; char *tmp = _readBufPtr; _readBufPtr = _readBufEnd; printPrompt(); cout << _readBuf; moveBufPtr(tmp); } 7. When you use output directing operator “>” to store the output of your program to a file, please note that only “standard output” is directed. The error message (i.e. “standard error” cerr) is not included. For “csh/tcsh”, you need to use “>&” instead. For bash, you can try “&>” or something like: “./mydb-ref -File dofile.ref > out.mine 2>&1” or “./mydb-ref -File dofile.ref 2>&1 | tee out.mine” 6. Grading We will test your submitted program with various combinations/sequences of commands to determine your grade. The results (i.e. outputs) will be compared with our reference program. Minor difference due to printing alignment, spacing, etc can be tolerated. However, to assist TAs for easier grading work, please try to match your output with ours.