There are other places where the symbol table could change. For
example, the loop in eval_string in oct-parse.yy, which is similar to
the one in main_loop in toplev.cc and the one in get_debug_input in
input.cc. Command history can also change in get_debug_input, though
I don't think it should be changing in eval_string.
Why not invoke the callback there, too? For interactive use, ie. I sit at the octave console and type command for command invoking the callback there was sufficient. It's a question of taste on how you would like to update the symbol table: More updates means decreasing octave performance. I would opt in for performance. From a practical point of view, I might be interested in the current workspace when doing the following things:
1.) Working interactively at the octave console.
2.) Debugging a script, walking step by step and watching the workspace change.
There is not need to update the symbol table model (which needs to be processed from the symbol table) too often.