source: trunk/gsdl/src/mgpp/text/QueryParser.cpp@ 855

Last change on this file since 855 was 855, checked in by sjboddie, 24 years ago

Rodgers new C++ mg

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 5.9 KB
Line 
1/**************************************************************************
2 *
3 * QueryParser.cpp -- Query parser for a simple query language
4 * Copyright (C) 2000 Rodger McNab
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * $Id: QueryParser.cpp 855 2000-01-14 02:17:52Z sjboddie $
21 *
22 **************************************************************************/
23
24#include "QueryParser.h"
25#include "QueryLex.h"
26
27
28static QueryNode *ParseExpression (UCArray::const_iterator &here,
29 UCArray::const_iterator end);
30
31static QueryNode *AndAdd (QueryNode *t1, QueryNode *t2) {
32 if (t1 == NULL) return t2;
33 if (t2 == NULL) return t1;
34
35 AndQueryNode *andNode = new AndQueryNode;
36 andNode->leftNode = t1;
37 andNode->rightNode = t2;
38 return andNode;
39}
40
41static QueryNode *OrAdd (QueryNode *t1, QueryNode *t2) {
42 if (t1 == NULL) return t2;
43 if (t2 == NULL) return t1;
44
45 OrQueryNode *orNode = new OrQueryNode;
46 orNode->leftNode = t1;
47 orNode->rightNode = t2;
48 return orNode;
49}
50
51static QueryNode *NotAdd (QueryNode *t1, QueryNode *t2) {
52 if (t1 == NULL) return t2;
53 if (t2 == NULL) return t1;
54
55 NotQueryNode *notNode = new NotQueryNode;
56 notNode->queryNode = t1;
57 notNode->notNode = t2;
58 return notNode;
59}
60
61// expects the opening bracket to have already been parsed
62// and discarded
63static QueryNode *ParseBracketExpression (UCArray::const_iterator &here,
64 UCArray::const_iterator end) {
65 // get everything in the expression
66 QueryNode *curTree = ParseExpression (here, end);
67
68 // gobble up tokens until a closing bracket is found
69 // or the end of the string
70 LexEl el;
71 while (ParseLexEl (here, end, el)) {
72 if (el.lexType == CloseBracketE) break;
73 }
74
75 return curTree;
76}
77
78static int ParseInt (UCArray::const_iterator &here,
79 UCArray::const_iterator end) {
80 LexEl el;
81 UCArray::const_iterator oldHere = here;
82 if (ParseLexEl (here, end, el) && el.lexType == IntegerE)
83 return el.num;
84
85 here = oldHere; // not an integer
86 return 0;
87}
88
89
90static void ParseTermModifiers (UCArray::const_iterator &here,
91 UCArray::const_iterator end,
92 TermNode &termNode) {
93 LexEl el;
94 UCArray::const_iterator oldHere = here;
95 while (ParseLexEl (here, end, el)) {
96 if (el.lexType == TermWeightE) {
97 termNode.termWeight = ParseInt (here, end);
98
99 } else if (el.lexType == StemMethodE) {
100 termNode.stemMethod = ParseInt (here, end);
101
102 } else if (el.lexType == RangeE) {
103 termNode.startRange = ParseInt (here, end);
104 termNode.endRange = ParseInt (here, end);
105
106 } else if (el.lexType == AtE) {
107 termNode.startRange = termNode.endRange = ParseInt (here, end);
108
109 } else {
110 // no term modifiers
111 here = oldHere;
112 break;
113 }
114
115 oldHere = here;
116 }
117}
118
119// expects the starting quote to have been parsed
120// and discarded
121static void ParsePhrase (UCArray::const_iterator &here,
122 UCArray::const_iterator end,
123 ProxMatchQueryNode &proxNode) {
124 LexEl el;
125 while (ParseLexEl (here, end, el)) {
126 if (el.lexType == TermE || el.lexType == IntegerE) {
127 TermNode termNode;
128 termNode.term = el.text;
129 ParseTermModifiers (here, end, termNode);
130 proxNode.terms.push_back (termNode);
131
132 } else if (el.lexType == QuoteE) {
133 break;
134
135 } else {
136 // error
137 break;
138 }
139 }
140}
141
142static QueryNode *ParseTerm (UCArray::const_iterator &here,
143 UCArray::const_iterator end) {
144 LexEl el;
145
146 UCArray::const_iterator oldHere = here;
147 if (!ParseLexEl (here, end, el)) return NULL;
148
149 if (el.lexType == OpenBracketE)
150 return ParseBracketExpression (here, end);
151
152 ProxMatchQueryNode *proxNode = new ProxMatchQueryNode;
153
154 // check for a tag
155 if (el.lexType == TagE) {
156 oldHere = here; // don't backtrack past here
157 if (!ParseLexEl (here, end, el)) return NULL;
158 if (el.lexType == TermE) {
159 proxNode->tagNodePtr = new TagNode;
160 proxNode->tagNodePtr->tagName = el.text;
161 if (!ParseLexEl (here, end, el)) return NULL;
162 }
163 }
164
165 if (el.lexType == TermE || el.lexType == IntegerE) {
166 TermNode termNode;
167 termNode.term = el.text;
168 ParseTermModifiers (here, end, termNode);
169 proxNode->terms.push_back (termNode);
170 return proxNode;
171
172 } else if (el.lexType == QuoteE) {
173 ParsePhrase (here, end, *proxNode);
174 return proxNode;
175 }
176
177 // not a term
178 here = oldHere;
179 delete proxNode;
180 return NULL;
181}
182
183
184static QueryNode *ParseExpression (UCArray::const_iterator &here,
185 UCArray::const_iterator end) {
186 LexEl el;
187 QueryNode *curTree = NULL;
188
189 UCArray::const_iterator oldHere = here;
190 while (ParseLexEl (here, end, el)) {
191 if (el.lexType == OpenBracketE ||
192 el.lexType == TermE ||
193 el.lexType == QuoteE ||
194 el.lexType == IntegerE ||
195 el.lexType == TagE) {
196 // some type of term, back track and parse it
197 here = oldHere;
198 curTree = OrAdd (curTree, ParseTerm (here, end));
199
200 } else if (el.lexType == AndOpE) {
201 curTree = AndAdd (curTree, ParseTerm (here, end));
202
203 } else if (el.lexType == OrOpE) {
204 curTree = OrAdd (curTree, ParseTerm (here, end));
205
206 } else if (el.lexType == NotOpE) {
207 curTree = NotAdd (curTree, ParseTerm (here, end));
208
209 } else break;
210
211 oldHere = here;
212 }
213
214 return curTree;
215}
216
217QueryNode *ParseQuery (const UCArray &queryStr) {
218 UCArray::const_iterator here = queryStr.begin();
219 UCArray::const_iterator end = queryStr.end();
220 return ParseExpression (here, end);
221}
Note: See TracBrowser for help on using the repository browser.