Ниже показана трассировка его обработки. Финальным объектом в стеке _query_stack является объект класса NotQuery:
evalNot() : incomplete!
push on _current_op ( size == 1 )
evalWord() : daddy
pop _current_op : NotQuery
add operand: WordQuery : NotQuery complete!
push NotQuery on _query_stack
Текст, расположенный с отступом под функциями eval, показывает, как выполняется операция.
Во втором примере - составном запросе типа OrQuery - встречаются оба случая. Здесь же иллюстрируется помещение полного оператора в стек _query_stack:
== fiery || untamed || shyly
evalWord() : fiery
push word on _query_stack
evalOr() : incomplete!
pop _query_stack : fiery
add operand : WordQuery : OrQuery incomplete!
push OrQuery on _current_op ( size == 1 )
evalWord() : untamed
pop _current_op : OrQuery
add operand : WordQuery : OrQuery complete!
push OrQuery on _query_stack
evalOr() : incomplete!
pop _query_stack : OrQuery
add operand : OrQuery : OrQuery incomplete!
push OrQuery on _current_op ( size == 1 )
evalWord() : shyly
pop _current_op : OrQuery
add operand : WordQuery : OrQuery complete!
push OrQuery on _query_stack
В последнем примере рассматривается составной запрос и применение скобок для изменения порядка вычислений:
== fiery && ( bird || untamed )
evalWord() : fiery
push word on _query_stack
evalAnd() : incomplete!
pop _query_stack : fiery
add operand : WordQuery : AndQuery incomplete!
push AndQuery on _current_op ( size == 1 )
evalWord() : bird
_paren is set to 1
push word on _query_stack
evalOr() : incomplete!
pop _query_stack : bird
add operand : WordQuery : OrQuery incomplete!
push OrQuery on _current_op ( size == 2 )
evalWord() : untamed
pop _current_op : OrQuery
add operand : WordQuery : OrQuery complete!
push OrQuery on _query_stack
evalRParen() :
_paren: 0 _current_op.size(): 1
pop _query_stack : OrQuery
pop _current_op : AndQuery
add operand : OrQuery : AndQuery complete!
push AndQuery on _query_stack
Реализация системы текстового поиска состоит из трех компонентов:
класс TextQuery, где производится обработка текста (подробно он рассматривался в разделе 16.4). Для него нет производных классов;
объектно-ориентированная иерархия Query для представления и обработки различных типов запросов;
класс UserQuery, с помощью которого представлен конечный автомат для построения иерархии Query.
До настоящего момента мы реализовали эти три компонента практически независимо друг от друга и без каких бы то ни было конфликтов. Но, к сожалению, иерархия классов Query не поддерживает требований к конструированию объектов, предъявляемых реализацией UserQuery:
классы AndQuery, OrQuery и NotQuery требуют, чтобы каждый операнд присутствовал в момент определения объекта. Однако принятая нами схема обработки подразумевает наличие неполных объектов;
наша схема предполагает отложенное добавление операнда к объектам AndQuery, OrQuery и NotQuery. Более того, такая операция должна быть виртуальной. Операнд приходится добавлять через указатель типа Query*, находящийся в стеке _current_op. Однако способ добавления операнда зависит от типа: для унарных (NotQuery) и бинарных (AndQuery и OrQuery) операций он различен. Наша иерархия классов Query подобные операции не поддерживает.