Tuesday, February 10, 2015

Program – Dictionary Class Problem

While investigating how clean up the chain calling mentioned in the previous post, it was discovered that the dictionary class hierarchy with respect to the base class was not implemented correctly.  The following is the thought process on refactoring the call chain and how this dictionary problem was discovered.  Consider the current complete REM operand text function:
const std::string remOperandText(ProgramLineReader &programLineReader)
{
    auto operand = programLineReader();
    return programLineReader.unit()->remDictionary()->string(operand);
}
The encode and remove functions are similar except they have no return value and different dictionary functions are called.  The encode function has a back inserter iterator argument instead of a program reader and still has a program unit pointer argument.  To remove the call chain and make the code as readable as possible, the function could be changed to something like:
const std::string remOperandText(ProgramReader &programReader)
{
    return programReader.getStringFromRemDictionary();
}
Where the name of the program line reader class was going to be simplified (the "Line" part of the name added nothing significant and didn't seem appropriate since the program reader was now reading from a dictionary in addition to a program line).  There would be similar functions for adding and removing from the dictionary for the encode and remove functions.

The problem with this scheme is the number of functions needed.  Each of the other five codes have nearly identical table functions, except different dictionaries are used, for a total of 18 functions.  The Program Reader class will need 18 access functions, one for each table function.  Continuing this pattern will required many more table and access functions when the other codes are implemented (array, defined functions and user functions).

To reduce the number of the Program Reader class access functions to three (add to a dictionary, get string from a dictionary, and remove from a dictionary) will be to implement a enumeration for the dictionary types (remarks, constant numbers, constant strings, double variables, integer variables, string variables, and the rest of the unimplemented codes) and pass this to the access function.  The REM function would look something like:
const std::string remOperandText(ProgramReader &programReader)
{
    return programReader.getStringFrom(Rem_Dictionary);
}
For this implementation, the dictionaries in the program model will need to be placed into an indexable by enumerator container.  The program model will provide an access function to the dictionary by enumerator (there is currently one access function for each dictionary - six access functions).

The indexable container will need to contain pointers to the dictionaries.  The requires base class pointers to the dictionaries.  This is where the problem was discovered - the dictionary class does not have virtual functions.  This needs to corrected next.

To reduce the number of table functions to three (encode, operand text, and remove), the dictionary enumerator will be placed in the table entry.  The three virtual table functions will pass the dictionary enumerator from the table entry to the program reader function.  The intermediate Code With Operand table entry class will define these functions and the individual code classes (REM, constants, variables, etc.) will inherit them.  Now, the common operand text  function will look something like:
const std::string CodeWithOperand::perandText(ProgramReader &programReader)
{
    return programReader.getStringFrom(m_dictionaryType);
}