source: trunk/mgpp/text/QueryParser.cpp@ 3365

Last change on this file since 3365 was 3365, checked in by kjdon, 22 years ago

Initial revision

  • 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 **************************************************************************/
21
22#include "QueryParser.h"
23#include "QueryLex.h"
24
25
26static QueryNode *ParseExpression (UCArray::const_iterator &here,
27 UCArray::const_iterator end);
28
29static QueryNode *AndAdd (QueryNode *t1, QueryNode *t2) {
30 if (t1 == NULL) return t2;
31 if (t2 == NULL) return t1;
32
33 AndQueryNode *andNode = new AndQueryNode;
34 andNode->leftNode = t1;
35 andNode->rightNode = t2;
36 return andNode;
37}
38
39static QueryNode *OrAdd (QueryNode *t1, QueryNode *t2) {
40 if (t1 == NULL) return t2;
41 if (t2 == NULL) return t1;
42
43 OrQueryNode *orNode = new OrQueryNode;
44 orNode->leftNode = t1;
45 orNode->rightNode = t2;
46 return orNode;
47}
48
49static QueryNode *NotAdd (QueryNode *t1, QueryNode *t2) {
50 if (t1 == NULL) return t2;
51 if (t2 == NULL) return t1;
52
53 NotQueryNode *notNode = new NotQueryNode;
54 notNode->queryNode = t1;
55 notNode->notNode = t2;
56 return notNode;
57}
58
59// expects the opening bracket to have already been parsed
60// and discarded
61static QueryNode *ParseBracketExpression (UCArray::const_iterator &here,
62 UCArray::const_iterator end) {
63 // get everything in the expression
64 QueryNode *curTree = ParseExpression (here, end);
65
66 // gobble up tokens until a closing bracket is found
67 // or the end of the string
68 LexEl el;
69 while (ParseLexEl (here, end, el)) {
70 if (el.lexType == CloseBracketE) break;
71 }
72
73 return curTree;
74}
75
76static int ParseInt (UCArray::const_iterator &here,
77 UCArray::const_iterator end) {
78 LexEl el;
79 UCArray::const_iterator oldHere = here;
80 if (ParseLexEl (here, end, el) && el.lexType == IntegerE)
81 return el.num;
82
83 here = oldHere; // not an integer
84 return 0;
85}
86
87
88static void ParseTermModifiers (UCArray::const_iterator &here,
89 UCArray::const_iterator end,
90 TermNode &termNode) {
91 LexEl el;
92 UCArray::const_iterator oldHere = here;
93 while (ParseLexEl (here, end, el)) {
94 if (el.lexType == TermWeightE) {
95 termNode.termWeight = ParseInt (here, end);
96
97 } else if (el.lexType == StemMethodE) {
98 termNode.stemMethod = ParseInt (here, end);
99
100 } else if (el.lexType == RangeE) {
101 termNode.startRange = ParseInt (here, end);
102 termNode.endRange = ParseInt (here, end);
103
104 } else if (el.lexType == AtE) {
105 termNode.startRange = termNode.endRange = ParseInt (here, end);
106
107 } else {
108 // no term modifiers
109 here = oldHere;
110 break;
111 }
112
113 oldHere = here;
114 }
115}
116
117// expects the starting quote to have been parsed
118// and discarded
119static void ParsePhrase (UCArray::const_iterator &here,
120 UCArray::const_iterator end,
121 ProxMatchQueryNode &proxNode) {
122 LexEl el;
123 while (ParseLexEl (here, end, el)) {
124 if (el.lexType == TermE || el.lexType == IntegerE) {
125 TermNode termNode;
126 termNode.term = el.text;
127 ParseTermModifiers (here, end, termNode);
128 proxNode.terms.push_back (termNode);
129
130 } else if (el.lexType == QuoteE) {
131 break;
132
133 } else {
134 // error
135 break;
136 }
137 }
138}
139
140static QueryNode *ParseTerm (UCArray::const_iterator &here,
141 UCArray::const_iterator end) {
142 LexEl el;
143
144 UCArray::const_iterator oldHere = here;
145 if (!ParseLexEl (here, end, el)) return NULL;
146
147 if (el.lexType == OpenBracketE)
148 return ParseBracketExpression (here, end);
149
150 ProxMatchQueryNode *proxNode = new ProxMatchQueryNode;
151
152 // check for a tag
153 if (el.lexType == TagE) {
154 oldHere = here; // don't backtrack past here
155 if (!ParseLexEl (here, end, el)) return NULL;
156 if (el.lexType == TermE) {
157 proxNode->tagNodePtr = new TagNode;
158 proxNode->tagNodePtr->tagName = el.text;
159 if (!ParseLexEl (here, end, el)) return NULL;
160 }
161 }
162
163 if (el.lexType == TermE || el.lexType == IntegerE) {
164 TermNode termNode;
165 termNode.term = el.text;
166 ParseTermModifiers (here, end, termNode);
167 proxNode->terms.push_back (termNode);
168 return proxNode;
169
170 } else if (el.lexType == QuoteE) {
171 ParsePhrase (here, end, *proxNode);
172 return proxNode;
173 }
174
175 // not a term
176 here = oldHere;
177 delete proxNode;
178 return NULL;
179}
180
181
182static QueryNode *ParseExpression (UCArray::const_iterator &here,
183 UCArray::const_iterator end) {
184 LexEl el;
185 QueryNode *curTree = NULL;
186
187 UCArray::const_iterator oldHere = here;
188 while (ParseLexEl (here, end, el)) {
189 if (el.lexType == OpenBracketE ||
190 el.lexType == TermE ||
191 el.lexType == QuoteE ||
192 el.lexType == IntegerE ||
193 el.lexType == TagE) {
194 // some type of term, back track and parse it
195 here = oldHere;
196 curTree = OrAdd (curTree, ParseTerm (here, end));
197
198 } else if (el.lexType == AndOpE) {
199 curTree = AndAdd (curTree, ParseTerm (here, end));
200
201 } else if (el.lexType == OrOpE) {
202 curTree = OrAdd (curTree, ParseTerm (here, end));
203
204 } else if (el.lexType == NotOpE) {
205 curTree = NotAdd (curTree, ParseTerm (here, end));
206
207 } else break;
208
209 oldHere = here;
210 }
211
212 return curTree;
213}
214
215QueryNode *ParseQuery (const UCArray &queryStr) {
216 UCArray::const_iterator here = queryStr.begin();
217 UCArray::const_iterator end = queryStr.end();
218 return ParseExpression (here, end);
219}
Note: See TracBrowser for help on using the repository browser.