2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * $XConsortium: ParseTree.cc /main/3 1996/06/11 16:21:40 cde-hal $
26 * Copyright (c) 1991 HaL Computer Systems, Inc. All rights reserved.
27 * UNPUBLISHED -- rights reserved under the Copyright Laws of the United
28 * States. Use of a copyright notice is precautionary only and does not
29 * imply publication or disclosure.
31 * This software contains confidential information and trade secrets of HaL
32 * Computer Systems, Inc. Use, disclosure, or reproduction is prohibited
33 * without the prior express written permission of HaL Computer Systems, Inc.
35 * RESTRICTED RIGHTS LEGEND
36 * Use, duplication, or disclosure by the Government is subject to
37 * restrictions as set forth in subparagraph (c)(l)(ii) of the Rights in
38 * Technical Data and Computer Software clause at DFARS 252.227-7013.
39 * HaL Computer Systems, Inc.
40 * 1315 Dell Avenue, Campbell, CA 95008
47 #include "../Prelude.h"
53 const ClassType T::T/**/Class = (ClassType *) &T::T/**/Class
56 const ClassType T::T##Class = (ClassType *) &T::T##Class
59 #define InitLeaf(T,P) \
60 InitBase (T); const int T::f_precedence = P
61 #define InitLeafS(T,P,S) \
62 InitBase (T); const int T::f_precedence = P; char *T::f_symbol = S
64 bool PNode::f_recursive_delete = FALSE;
67 InitBase (PBooleanOp);
70 InitBase (PPostfixOp);
74 InitLeafS (PWeight, 7, " weight " );
75 InitLeafS (PProximity, 7, " within " );
76 InitLeafS (PNotBoth, 7, " not_both" );
77 InitLeafS (PStart, 0, "(" );
78 InitLeafS (PEnd, 0, ")" );
79 InitLeaf (PGroup, 0 );
80 InitLeafS (PNot, 5, "not " );
81 InitLeafS (PNear, 4, " near " );
82 InitLeafS (PBefore, 4, " before " );
83 InitLeafS (PAnd, 3, " and " );
84 InitLeafS (POr, 2, " or " );
85 InitLeaf (PString, 8 );
86 InitLeaf (PNumber, 8 );
88 // /////////////////////////////////////////////////////////////////
90 // /////////////////////////////////////////////////////////////////
92 PNode::PNode (PNode *parent, PNode *previous, PNode *next)
93 : f_parent (parent), f_previous (previous), f_next (next)
95 /* Modify previous and next links of previous and next */
96 if (f_previous != NULL)
97 f_previous->f_next = this;
99 f_next->f_previous = this;
102 PText::PText (PNode *parent, PNode *previous, PNode *next, char *str)
103 : PNode (parent, previous, next)
110 f_symbol_len = strlen (str);
111 if (f_symbol_len < 32)
114 f_symbol_space = f_symbol_len;
116 int len = sizeof(char) * f_symbol_space;
117 f_symbol = (char *) malloc (len + sizeof(char));
118 *((char *) memcpy(f_symbol, str, len) + len) = '\0';
122 PString::PString (PNode *parent, PNode *previous, PNode *next, char *str)
123 : PText (parent, previous, next, str)
127 PString::PString (char *str)
128 : PText (NULL, NULL, NULL, str)
131 PNumber::PNumber (PNode *parent, PNode *previous, PNode *next, char *str)
132 : PText (parent, previous, next, str)
135 PGroup::PGroup (PNode *parent, PNode *previous, PNode *next, PNode *subexpr)
136 : PNode (parent, NULL, NULL),
137 f_left (new PStart (this, previous, subexpr)),
139 f_right (new PEnd (this, subexpr, next))
141 subexpr->f_parent = this;
144 PRoot::PRoot (PNode *subexpr)
145 : PGroup (NULL, NULL, NULL, subexpr), f_length (0)
148 f_char_of = (char *) malloc (sizeof (char) * (f_space + 1));
149 f_node_of_real = (PNode **) malloc (sizeof (PNode *) * (f_space + 2));
150 f_node_of = f_node_of_real + 1;
153 PPrefixOp::PPrefixOp (PNode *rhs)
154 : PNode (rhs->f_parent, rhs->f_previous, rhs)
156 /* fix up the parent and previous of rhs */
157 rhs->f_parent = this;
160 PNot::PNot (PNode *rhs)
166 PBooleanOp::PBooleanOp ()
167 : PNode (NULL, NULL, NULL)
170 // NOTE: clean up PNode constructors later (make NULL constructor, etc.)
172 PBooleanOp::init (PRoot *root, long pos)
174 PNode *lhs = root->f_node_of[pos-1];
175 PNode *rhs = root->f_node_of[pos];
177 /* Expects eother lhs or rhs to be NULL, to indicate where to insert
179 /* The new string will be on the lhs of the op and it's
180 previous will become the previous of the existing rhs.
182 previous-thing <cursor> rhs <--- Before
183 previous-thing new-lhs op <cursor> rhs <--- After
185 The next of rhs does not change. The next of the new-lhs
186 and the previous of rhs will be set in the PNode constructor
187 when the op is created. The second case below is exactly
188 opposite to this one, eg:
190 lhs <cursor> next-thing <--- Before
191 lhs op new-rhs <cursor> next-thing <--- After
194 // First check to see of right side is valid operand
195 if (rhs->isa (PString::PStringClass))
198 f_left = new PString (this, rhs->f_previous, this);
200 // Make rhs a child and fix next/previous pointers.
202 rhs->f_previous = this;
204 // Become a child of the rhs' parent
205 rhs->f_parent->replace_child (rhs, this);
207 // Make rhs a child of this
208 rhs->f_parent = this;
211 // Now see if left side is valid operand
212 else if (lhs->isa (PString::PStringClass))
215 f_right = new PString (this, this, lhs->f_next);
217 // Make lhs a child and fix previous/next pointers.
221 // Become a child of the lhs' parent
222 lhs->f_parent->replace_child (lhs, this);
224 // Make the lhs a child of this
225 lhs->f_parent = this;
230 puts ("ERROR: lhs and rhs both non NULL in Boolean Op constructor");
234 /* -------- Handle precedence -------- */
236 while (f_parent->isa (PBooleanOp::PBooleanOpClass) &&
237 (f_parent->precedence() > precedence()))
240 // Reparent based on the side of parent this is on
241 PBooleanOp *old_parent = (PBooleanOp *) f_parent;
242 // My f_parent pointer changed by next function call
243 old_parent->f_parent->replace_child (old_parent, this);
245 if (old_parent->f_left == this)
247 old_parent->replace_child (this, f_right);
248 f_right = old_parent;
249 old_parent->f_parent = this;
251 else if (old_parent->f_right == this)
253 old_parent->replace_child (this, f_left);
255 old_parent->f_parent = this;
259 puts ("ERROR: bogousity in precedence handling");
266 // /////////////////////////////////////////////////////////////////
268 // /////////////////////////////////////////////////////////////////
272 /* fix up next / previous links */
274 f_previous->f_next = f_next;
276 f_next->f_previous = f_previous;
289 if (f_recursive_delete)
297 free ((char *) f_char_of);
298 free ((char *) f_node_of_real);
304 // Stick the child of not in not's parent (in not's slot)
305 f_parent->replace_child (this, f_operand);
309 PNot::delete_self (delete_request_t request)
311 PNode *previous = f_previous;
313 if (request == OBJECT_REQUEST)
314 previous->delete_self (OBJECT_REQUEST);
319 // Don't let parent keep a pointer to me
320 f_parent->replace_child (this, NULL);
324 // NOTE: need to add check for deleting first thing before a group.
325 // NOTE: may need a way to return "failed"
327 PText::delete_self (delete_request_t request)
329 PNode *previous = f_previous;
331 if (request == USER_REQUEST)
332 previous->delete_self (OBJECT_REQUEST);
336 PBooleanOp::delete_self (delete_request_t request)
338 if (request == USER_REQUEST)
339 f_previous->delete_self (OBJECT_REQUEST);
341 // Take this out of next/previous chain
342 f_next->f_previous = f_previous;
343 f_previous->f_next = f_next;
344 // f_parent->replace_child (this, NULL);
346 /* When an operator is deleted part of the parse tree is split.
347 To reconstruct the parse tree, the former left and right side
350 // The first operator needing a child will be the parent of the
353 // (Yes, operater is spelled wrong, but only because the correct spelling
354 // is a C++ reserved word...)
356 PNode *operater, *operand;
358 /* -------- Figure out operand and operators. -------- */
362 else if (f_right == NULL)
366 if (f_next->isa (PBooleanOp::PBooleanOpClass))
369 // operand was on left of operater, find new operand
370 operand = this->f_left;
371 while (operand->isa (PBooleanOp::PBooleanOpClass))
372 operand = ((PBooleanOp *) operand)->f_right;
374 else if (f_previous->isa (PBooleanOp::PBooleanOpClass))
376 operater = f_previous;
377 // operand was on right of operater, find new operand
378 operand = this->f_right;
379 while (operand->isa (PBooleanOp::PBooleanOpClass))
380 operand = ((PBooleanOp *) operand)->f_left;
385 /* -------- Merge subtrees until only one tree remains -------- */
387 while (f_left != NULL && f_right != NULL)
389 // Now find enclosing subtree of operand based on precedence.
390 // We can't move the operand to the operator if it is already
391 // under an operator with higher precedence.
392 while (operand->f_parent != this
393 && operand->f_parent->precedence() >= operater->precedence())
395 operand = operand->f_parent;
397 // Now operand points to the subtree we can safely reparent
398 PNode *old_parent = operand->f_parent;
400 // Empty the spot where the subtree was
401 operand->f_parent->replace_child (operand, NULL);
403 // Replace hole in operator with this subtree
404 operater->replace_child (NULL, operand);
406 // The new operand is the old operator...
407 operand = operater->f_parent;
409 // and the new operator is the old operand because it just lost a subtree
410 operater = old_parent;
413 // Finally get rid of this
415 f_parent->replace_child (this, f_right);
417 f_parent->replace_child (this, f_left);
418 f_previous = f_next = NULL;
422 // /////////////////////////////////////////////////////////////////
424 // /////////////////////////////////////////////////////////////////
427 PText::insert_chars (int where, char *text, int length)
429 int new_len = f_symbol_len + length;
432 /* -------- allocate memory if necessary -------- */
433 if (new_len > f_symbol_space)
435 // keep doubling until we have enough space
436 while (new_len > f_symbol_space)
438 // NOTE: check malloc result
439 f_symbol = (char *) realloc ((char *) f_symbol,
440 sizeof (char) * (f_symbol_space + 1));
443 /* -------- make room for new stuff -------- */
444 bcopy (&f_symbol[where], // from
445 &f_symbol[where+length], // to
446 f_symbol_len - where + 1); // length
448 /* -------- insert new stuff -------- */
449 bcopy (text, &f_symbol[where], length);
450 f_symbol_len += length;
454 PText::remove_chars (int where, int len)
456 /* Just copy stuff after hole back over it. */
457 bcopy (&f_symbol[where+len], &f_symbol[where],
458 f_symbol_len - (where + len) + 1);
460 if (f_symbol_len == 2) // ie: just two quotes
464 // /////////////////////////////////////////////////////////////////
466 // /////////////////////////////////////////////////////////////////
468 #define LEFT_SIDE (root->f_node_of[pos-1])
469 #define RIGHT_SIDE (root->f_node_of[pos])
470 #define LEFT_ISA(X) ((root->f_node_of[pos-1])->isa (X))
471 #define RIGHT_ISA(X) ((root->f_node_of[pos])->isa (X))
474 PNot::insert (PRoot *root, long pos)
476 puts ("Inserting a not");
477 PNode *rhs = RIGHT_SIDE;
478 PNot *not = new PNot (rhs);
479 not->f_parent->replace_child (rhs, not);
483 POr::insert (PRoot *root, long pos)
489 PAnd::insert (PRoot *root, long pos)
491 new PAnd (root, pos);
495 PNear::insert (PRoot *root, long pos)
497 new PNear (root, pos);
501 PBefore::insert (PRoot *root, long pos)
503 new PBefore (root, pos);
507 PNode::insert (PRoot *, long)
509 puts ("Tried to insert something with no insert method.");
512 // /////////////////////////////////////////////////////////////////
514 // /////////////////////////////////////////////////////////////////
517 PNode::can_insert (PRoot *, long)
523 PBooleanOp::can_insert (PRoot *root, long pos)
525 /* If one side or the other is text, but not both, can do */
526 if ((LEFT_ISA (PText::PTextClass) && !RIGHT_ISA (PText::PTextClass)) ||
527 (!LEFT_ISA (PText::PTextClass) && RIGHT_ISA (PText::PTextClass)))
533 PWeight::can_insert (PRoot *root, long pos)
535 return (FALSE);// tmp fix
536 /* If left side is string and the right side isn't can do */
537 if (LEFT_ISA (PString::PStringClass) &&
538 !RIGHT_ISA (PText::PTextClass) &&
539 !RIGHT_ISA (PWeight::PWeightClass))
546 PNot::can_insert (PRoot *root, long pos)
548 /* "not" insertable if rhs is a string and lhs isn't */
549 if (LEFT_ISA (PText::PTextClass) || LEFT_ISA (PNot::PNotClass))
551 if (RIGHT_ISA (PString::PStringClass) || RIGHT_ISA (PStart::PStartClass))
556 // /////////////////////////////////////////////////////////////////
557 // replace child functions
558 // /////////////////////////////////////////////////////////////////
561 PBooleanOp::replace_child (PNode *old, PNode *replacement)
564 f_left = replacement;
565 else if (f_right == old)
566 f_right = replacement;
569 puts ("ERROR: invalid old child passed to PBooleanOp::replace_child");
572 if (replacement != NULL)
573 replacement->f_parent = this;
576 // /////////////////////////////////////////////////////////////////
578 // /////////////////////////////////////////////////////////////////
587 /* go through the list of displayable elements */
588 for (p = f_left->f_next; p != f_right; p = p->f_next)
590 /* add the symbol for this element to the string */
591 printf ("adding symbol: <%s>\n", p->symbol());
592 for (s = p->symbol(); *s != '\0'; s++)
598 realloc ((char *) f_char_of, sizeof(char) * (f_space + 1));
599 f_node_of_real = (PNode **)
600 realloc ((char *) f_node_of_real,
601 sizeof(PNode *) * (f_space + 2));
602 f_node_of = f_node_of_real + 1;
609 /* fill in boundries */
610 f_char_of[pos] = '\0';
611 f_node_of[-1] = f_left;
612 f_node_of[pos] = f_right;
613 f_old_length = f_length;
615 // ON_DEBUG (printf ("Generated: <%s>\n", f_char_of);)