The done stack of the translator is used for temporarily holding RPN items appended to the RPN output list to be consumed as operands by operators, functions and commands. This will be the next stack changed to
std::stack. But first some realignment was required to move functionality from the
Done Stack class to the
Done Item structure. Like the
Hold Stack, the
Done Stack also has
QStack as its base class with functionality added. Unlike the
Hold Stack class, this added functionality did more than just add stack convenience functions.
Each item on the done stack contains a shared pointer to the RPN item plus token pointers to the first and last token of the expression of the RPN item, which may contain open and closing parentheses tokens that will eventually be dropped (in most cases). These are for reporting errors to an entire expression including open and closing parentheses. The parentheses token are deleted when they are no longer needed. A closing parentheses is not deleted for extra parentheses that need recreated.
The non-stack functionality added was for handling these first and last tokens. The added
pop function only returned the RPN item of the done item popped from the stack, but also deleted the first and last tokens if they contained parentheses (checking if unused for the last token). Similarly, the
drop function also deleted the first and last tokens if parentheses. These called functions in
Done Item structure to do the check and delete of the tokens. The final non-stack function replaced the first and last tokens of the done item on top of the stack.
This non-stack functionality was moved to the
Done Item structure. The
replace top first last function of the done stack called the
replace first and
replace last functions of the done item (the only caller to these functions). Each replace function deleted the token being replaced if a parentheses token. These functions were combined into a single
replace first last function, which is now called directly for the top item on the stack and the done stack function was removed.
The added
pop and
drop functions both deleted the first and last tokens if parentheses. These functions also decreased the size of the stack (by a stack pop or resize down one element). This would cause the destructor of the done item to be called. No destructor was declared, but since the RPN item was changed to a shared pointer, the compiler generated a default destructor to call the destructor of the shared pointer. The last and first token pointers were plain old data, so they were not affected. The delete parentheses calls were removed from the
pop and
drop functions, and added to a new done item destructor (the RPN item destructor is still handled automatically). However, this caused a curious problem in
pop function (a multiple deleted closing parentheses token), which now contained the single statement:
return QStack::pop().rpnItem;
The
pop() returns a copy of the done item on top of the stack. The item on top of the stack is then removed, which calls the new done item destructor for the item (deleting a closing parentheses in the last token pointer). The copy is used to get the RPN item, and then the copy goes out of scope, which calls the done item destructor. Since the copy has the same last parentheses token as the first, it gets erroneously deleted twice. This was happening previously, but since the [default] destructor was not affecting the first and last tokens, no double delete occurred. This was corrected by replacing the above statement with:
RpnItemPtr rpnItem = top().rpnItem;
drop();
return rpnItem;
Now a temporary of only the RPN item is made. The
drop() call resizes the stack down one item, causing the new destructor to be called, deleting the last token holding an unused closing parentheses. The RPN item is then returned. This also matches the operations that will be required for
std::stack. These specialized delete parentheses token functions won't be needed once shared pointers are used for token pointers.
[branch cpp11 commit
c23603ea2e]