Main
 

Main

The main function drives the whole thing. Its overall structure hasn’t changed much since our last iteration--except for the addition of the function table, the symbol table and the store.
const int maxBuf = 100;
const int maxSymbols = 40;

int main ()
{
    // Notice all these local objects.
    // A clear sign that there should be
    // a top level object, say, the Calculator.
    // Back to the drawing board!

    char buf [maxBuf];
    Status status;
    SymbolTable symTab (maxSymbols);
    FunctionTable funTab (symTab, funArr);
    Store store (maxSymbols, symTab);

    do
    {
        cout << "> ";  // prompt
        cin.getline (buf, maxBuf);
        Scanner scanner (buf);
        Parser  parser (scanner, store, funTab, symTab);
        status = parser.Eval ();
    } while (status != stQuit);
}

Notice that for every line of input we create a new scanner and a new parser. We keep however the same symbol table, function table and the store. This is important because we want the values assigned to variables to be remembered as long as the program is active. The parser’s destructor is called after the evaluation of every line. This call plays an important role of freeing the parse tree.

There is a comment at the top of main, which hints at ways of improving the structure of the program. There are five local variables/objects defined at the top of main. Moreover, they depend on each other: the symbol table has to be initialized before the function table and before the store. The parser’s constructor takes references to three of them. As a rule of thumb, whenever you see too many local variables, you should think hard how to combine at least some of them into a separate object. In our case, it's pretty obvious that this object sould be called Calculator. It should combine SymbolTable, FunctionTable and Store as its embeddings.

We’ll come back to this program in the next part of the book to see how it can be made into a professional, "industrial strength" program.
Next.