00001
00002
00003
00004
00005
00006 #line 1 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <config.h>
00029
00030 #include "omassert.h"
00031 #include "queryparser_internal.h"
00032 #include <xapian/error.h>
00033 #include <xapian/unicode.h>
00034 #include "stringutils.h"
00035
00036
00037 #include "queryparser_token.h"
00038
00039 #include <algorithm>
00040 #include <list>
00041 #include <string>
00042
00043 #include <string.h>
00044
00045 using namespace std;
00046
00047 using namespace Xapian;
00048
00049 inline bool
00050 U_isupper(unsigned ch) {
00051 return (ch < 128 && C_isupper((unsigned char)ch));
00052 }
00053
00054 inline bool
00055 U_isdigit(unsigned ch) {
00056 return (ch < 128 && C_isdigit((unsigned char)ch));
00057 }
00058
00059 inline bool
00060 U_isalpha(unsigned ch) {
00061 return (ch < 128 && C_isalpha((unsigned char)ch));
00062 }
00063
00064 using Xapian::Unicode::is_whitespace;
00065
00066 inline bool
00067 is_not_whitespace(unsigned ch) {
00068 return !is_whitespace(ch);
00069 }
00070
00071 using Xapian::Unicode::is_wordchar;
00072
00073 inline bool
00074 is_not_wordchar(unsigned ch) {
00075 return !is_wordchar(ch);
00076 }
00077
00078 inline bool
00079 is_digit(unsigned ch) {
00080 return (Unicode::get_category(ch) == Unicode::DECIMAL_DIGIT_NUMBER);
00081 }
00082
00083
00084
00085 inline bool
00086 is_suffix(unsigned ch) {
00087 return ch == '+' || ch == '#';
00088 }
00089
00090 inline bool
00091 prefix_needs_colon(const string & prefix, unsigned ch)
00092 {
00093 if (!U_isupper(ch)) return false;
00094 string::size_type len = prefix.length();
00095 return (len > 1 && prefix[len - 1] != ':');
00096 }
00097
00098 using Unicode::is_currency;
00099
00101 struct filter_group_id {
00105 list<string> prefixes;
00106
00110 Xapian::valueno valno;
00111
00113 explicit filter_group_id(const list<string> & prefixes_)
00114 : prefixes(prefixes_), valno(Xapian::BAD_VALUENO) {}
00115
00117 explicit filter_group_id(Xapian::valueno valno_)
00118 : prefixes(), valno(valno_) {}
00119
00121 bool operator<(const filter_group_id & other) const {
00122 if (prefixes != other.prefixes) {
00123 return prefixes < other.prefixes;
00124 }
00125 return valno < other.valno;
00126 }
00127 };
00128
00135 class Term {
00136 State * state;
00137
00138 public:
00139 string name;
00140 list<string> prefixes;
00141 string unstemmed;
00142 QueryParser::stem_strategy stem;
00143 termpos pos;
00144
00145 Term(const string &name_, termpos pos_) : name(name_), stem(QueryParser::STEM_NONE), pos(pos_) { }
00146 Term(const string &name_) : name(name_), stem(QueryParser::STEM_NONE), pos(0) { }
00147 Term(const string &name_, const list<string> &prefixes_)
00148 : name(name_), prefixes(prefixes_), stem(QueryParser::STEM_NONE), pos(0) { }
00149 Term(termpos pos_) : stem(QueryParser::STEM_NONE), pos(pos_) { }
00150 Term(State * state_, const string &name_, const list<string> &prefixes_,
00151 const string &unstemmed_,
00152 QueryParser::stem_strategy stem_ = QueryParser::STEM_NONE,
00153 termpos pos_ = 0)
00154 : state(state_), name(name_), prefixes(prefixes_), unstemmed(unstemmed_),
00155 stem(stem_), pos(pos_) { }
00156
00157 std::string make_term(const string & prefix) const;
00158
00159 void need_positions() {
00160 if (stem == QueryParser::STEM_SOME) stem = QueryParser::STEM_NONE;
00161 }
00162
00163 termpos get_termpos() const { return pos; }
00164
00165 filter_group_id get_filter_group_id() const { return filter_group_id(prefixes); }
00166
00167 Query * as_wildcarded_query(State * state) const;
00168
00169 Query * as_partial_query(State * state_) const;
00170
00171 Query get_query() const;
00172
00173 Query get_query_with_synonyms() const;
00174
00175 Query get_query_with_auto_synonyms() const;
00176 };
00177
00179 class State {
00180 QueryParser::Internal * qpi;
00181
00182 public:
00183 Query query;
00184 const char * error;
00185 unsigned flags;
00186
00187 State(QueryParser::Internal * qpi_, unsigned flags_)
00188 : qpi(qpi_), error(NULL), flags(flags_) { }
00189
00190 string stem_term(const string &term) {
00191 return qpi->stemmer(term);
00192 }
00193
00194 void add_to_stoplist(const Term * term) {
00195 qpi->stoplist.push_back(term->name);
00196 }
00197
00198 void add_to_unstem(const string & term, const string & unstemmed) {
00199 qpi->unstem.insert(make_pair(term, unstemmed));
00200 }
00201
00202 valueno value_range(Query & q, Term *a, Term *b) {
00203 string start = a->name;
00204 string end = b->name;
00205 Xapian::valueno valno = Xapian::BAD_VALUENO;
00206 list<ValueRangeProcessor *>::const_iterator i;
00207 for (i = qpi->valrangeprocs.begin(); i != qpi->valrangeprocs.end(); ++i) {
00208 valno = (**i)(start, end);
00209 if (valno != Xapian::BAD_VALUENO) {
00210 delete a;
00211 delete b;
00212 q = Query(Query::OP_VALUE_RANGE, valno, start, end);
00213 return valno;
00214 }
00215 }
00216
00217
00218
00219
00220
00221
00222 error = "Unknown range operation";
00223 return valno;
00224 }
00225
00226 Query::op default_op() const { return qpi->default_op; }
00227
00228 bool is_stopword(const Term *term) const {
00229 return qpi->stopper && (*qpi->stopper)(term->name);
00230 }
00231
00232 Database get_database() const {
00233 return qpi->db;
00234 }
00235 };
00236
00237 string
00238 Term::make_term(const string & prefix) const
00239 {
00240 string term;
00241 if (stem == QueryParser::STEM_SOME) term += 'Z';
00242 if (!prefix.empty()) {
00243 term += prefix;
00244 if (prefix_needs_colon(prefix, name[0])) term += ':';
00245 }
00246 if (stem != QueryParser::STEM_NONE) {
00247 term += state->stem_term(name);
00248 } else {
00249 term += name;
00250 }
00251
00252 if (!unstemmed.empty())
00253 state->add_to_unstem(term, unstemmed);
00254 return term;
00255 }
00256
00257 Query
00258 Term::get_query_with_synonyms() const
00259 {
00260 Query q = get_query();
00261
00262
00263 list<string>::const_iterator piter;
00264 for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
00265
00266 string term;
00267 if (!piter->empty()) {
00268 term += *piter;
00269 if (prefix_needs_colon(*piter, name[0])) term += ':';
00270 }
00271 term += name;
00272
00273 Xapian::Database db = state->get_database();
00274 Xapian::TermIterator syn = db.synonyms_begin(term);
00275 Xapian::TermIterator end = db.synonyms_end(term);
00276 if (syn == end && stem != QueryParser::STEM_NONE) {
00277
00278 term = 'Z';
00279 if (!piter->empty()) {
00280 term += *piter;
00281 if (prefix_needs_colon(*piter, name[0])) term += ':';
00282 }
00283 term += state->stem_term(name);
00284 syn = db.synonyms_begin(term);
00285 end = db.synonyms_end(term);
00286 }
00287 while (syn != end) {
00288 q = Query(Query::OP_OR, q, Query(*syn, 1, pos));
00289 ++syn;
00290 }
00291 }
00292 return q;
00293 }
00294
00295 Query
00296 Term::get_query_with_auto_synonyms() const
00297 {
00298 if (state->flags & QueryParser::FLAG_AUTO_SYNONYMS)
00299 return get_query_with_synonyms();
00300
00301 return get_query();
00302 }
00303
00304 static void
00305 add_to_query(Query *& q, Query::op op, Query * term)
00306 {
00307 Assert(term);
00308 if (q) {
00309 *q = Query(op, *q, *term);
00310 delete term;
00311 } else {
00312 q = term;
00313 }
00314 }
00315
00316 static void
00317 add_to_query(Query *& q, Query::op op, const Query & term)
00318 {
00319 if (q) {
00320 *q = Query(op, *q, term);
00321 } else {
00322 q = new Query(term);
00323 }
00324 }
00325
00326 Query
00327 Term::get_query() const
00328 {
00329 Assert(prefixes.size() >= 1);
00330 list<string>::const_iterator piter = prefixes.begin();
00331 Query q(make_term(*piter), 1, pos);
00332 while (++piter != prefixes.end()) {
00333 q = Query(Query::OP_OR, q, Query(make_term(*piter), 1, pos));
00334 }
00335 return q;
00336 }
00337
00338 Query *
00339 Term::as_wildcarded_query(State * state_) const
00340 {
00341 Database db = state_->get_database();
00342 vector<Query> subqs;
00343 list<string>::const_iterator piter;
00344 for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
00345 string root = *piter;
00346 root += name;
00347 TermIterator t = db.allterms_begin(root);
00348 while (t != db.allterms_end(root)) {
00349 subqs.push_back(Query(*t, 1, pos));
00350 ++t;
00351 }
00352 }
00353 delete this;
00354 return new Query(Query::OP_OR, subqs.begin(), subqs.end());
00355 }
00356
00357 Query *
00358 Term::as_partial_query(State * state_) const
00359 {
00360 Database db = state_->get_database();
00361 vector<Query> subqs;
00362 list<string>::const_iterator piter;
00363 for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
00364 string root = *piter;
00365 root += name;
00366 TermIterator t = db.allterms_begin(root);
00367 while (t != db.allterms_end(root)) {
00368 subqs.push_back(Query(*t, 1, pos));
00369 ++t;
00370 }
00371
00372 subqs.push_back(Query(make_term(*piter), 1, pos));
00373 }
00374 delete this;
00375 return new Query(Query::OP_OR, subqs.begin(), subqs.end());
00376 }
00377
00378 inline bool
00379 is_phrase_generator(unsigned ch)
00380 {
00381
00382
00383
00384 return (ch && ch < 128 && strchr(".-/:\\@", ch) != NULL);
00385 }
00386
00387 inline bool
00388 is_stem_preventer(unsigned ch)
00389 {
00390 return (ch && ch < 128 && strchr("(/\\@<>=*[{\"", ch) != NULL);
00391 }
00392
00393 inline bool
00394 should_stem(const std::string & term)
00395 {
00396 const unsigned int SHOULD_STEM_MASK =
00397 (1 << Unicode::LOWERCASE_LETTER) |
00398 (1 << Unicode::TITLECASE_LETTER) |
00399 (1 << Unicode::MODIFIER_LETTER) |
00400 (1 << Unicode::OTHER_LETTER);
00401 Utf8Iterator u(term);
00402 return ((SHOULD_STEM_MASK >> Unicode::get_category(*u)) & 1);
00403 }
00404
00405 inline unsigned check_infix(unsigned ch) {
00406 if (ch == '\'' || ch == '&' || ch == 0xb7 || ch == 0x5f4 || ch == 0x2027) {
00407
00408
00409
00410
00411 return ch;
00412 }
00413
00414
00415 if (ch == 0x2019 || ch == 0x201b) return '\'';
00416 return 0;
00417 }
00418
00419 inline unsigned check_infix_digit(unsigned ch) {
00420
00421 switch (ch) {
00422 case ',':
00423 case '.':
00424 case ';':
00425 case 0x037e:
00426 case 0x0589:
00427 case 0x060D:
00428 case 0x07F8:
00429 case 0x2044:
00430 case 0xFE10:
00431 case 0xFE13:
00432 case 0xFE14:
00433 return ch;
00434 }
00435 return 0;
00436 }
00437
00438 struct yyParser;
00439
00440
00441 static yyParser *ParseAlloc();
00442 static void ParseFree(yyParser *);
00443 static void Parse(yyParser *, int, Term *, State *);
00444
00445 void
00446 QueryParser::Internal::add_prefix(const string &field, const string &prefix,
00447 bool filter)
00448 {
00449 map<string, PrefixInfo>::iterator p = prefixmap.find(field);
00450 if (p == prefixmap.end()) {
00451 prefixmap.insert(make_pair(field, PrefixInfo(filter, prefix)));
00452 } else {
00453
00454 if (p->second.filter != filter) {
00455 throw Xapian::InvalidOperationError("Can't use add_prefix() and add_bool_prefix() on the same field name");
00456 }
00457 p->second.prefixes.push_back(prefix);
00458 }
00459 }
00460
00461 string
00462 QueryParser::Internal::parse_term(Utf8Iterator &it, const Utf8Iterator &end,
00463 bool &was_acronym)
00464 {
00465 string term;
00466
00467
00468 if (U_isupper(*it)) {
00469 string t;
00470 Utf8Iterator p = it;
00471 do {
00472 Unicode::append_utf8(t, *p++);
00473 } while (p != end && *p == '.' && ++p != end && U_isupper(*p));
00474
00475
00476 if (t.length() > 1) {
00477
00478
00479
00480 if (p == end || !is_wordchar(*p)) {
00481 it = p;
00482 swap(term, t);
00483 }
00484 }
00485 }
00486 was_acronym = !term.empty();
00487
00488 if (term.empty()) {
00489 unsigned prevch = *it;
00490 Unicode::append_utf8(term, prevch);
00491 while (++it != end) {
00492 unsigned ch = *it;
00493 if (!is_wordchar(ch)) {
00494
00495
00496
00497 Utf8Iterator p = it;
00498 ++p;
00499 if (p == end || !is_wordchar(*p)) break;
00500 unsigned nextch = *p;
00501 if (is_digit(prevch) &&
00502 is_digit(nextch)) {
00503 ch = check_infix_digit(ch);
00504 } else {
00505 ch = check_infix(ch);
00506 }
00507 if (!ch) break;
00508 }
00509 Unicode::append_utf8(term, ch);
00510 prevch = ch;
00511 }
00512 if (it != end && is_suffix(*it)) {
00513 string suff_term = term;
00514 Utf8Iterator p = it;
00515
00516 do {
00517 if (suff_term.size() - term.size() == 3) {
00518 suff_term.resize(0);
00519 break;
00520 }
00521 suff_term += *p;
00522 } while (is_suffix(*++p));
00523 if (!suff_term.empty() && (p == end || !is_wordchar(*p))) {
00524
00525
00526
00527
00528 bool use_suff_term = false;
00529 string lc = Unicode::tolower(suff_term);
00530 if (db.term_exists(lc)) {
00531 use_suff_term = true;
00532 } else {
00533 lc = Unicode::tolower(term);
00534 if (!db.term_exists(lc)) use_suff_term = true;
00535 }
00536 if (use_suff_term) {
00537 term = suff_term;
00538 it = p;
00539 }
00540 }
00541 }
00542 }
00543 return term;
00544 }
00545
00546 Query
00547 QueryParser::Internal::parse_query(const string &qs, unsigned flags,
00548 const string &default_prefix)
00549 {
00550 yyParser * pParser = ParseAlloc();
00551
00552
00553 bool value_ranges;
00554 value_ranges = !valrangeprocs.empty() && (qs.find("..") != string::npos);
00555
00556 termpos term_pos = 1;
00557 Utf8Iterator it(qs), end;
00558
00559 State state(this, flags);
00560
00561
00562
00563 int correction_offset = 0;
00564 corrected_query.resize(0);
00565
00566
00567 list<const PrefixInfo *> prefix_stack;
00568
00569
00570
00571 const PrefixInfo def_pfx(false, default_prefix);
00572 {
00573 const PrefixInfo * default_prefixinfo = &def_pfx;
00574 if (default_prefix.empty()) {
00575 map<string, PrefixInfo>::const_iterator f = prefixmap.find("");
00576 if (f != prefixmap.end()) default_prefixinfo = &(f->second);
00577 }
00578
00579
00580 prefix_stack.push_back(default_prefixinfo);
00581 }
00582
00583 unsigned newprev = ' ';
00584 main_lex_loop:
00585 enum {
00586 DEFAULT, IN_QUOTES, IN_PREFIXED_QUOTES, IN_PHRASED_TERM, IN_GROUP
00587 } mode = DEFAULT;
00588 while (it != end && !state.error) {
00589 bool last_was_operator = false;
00590 if (false) {
00591 just_had_operator:
00592 if (it == end) break;
00593 last_was_operator = true;
00594 mode = DEFAULT;
00595 }
00596 if (mode == IN_PHRASED_TERM) mode = DEFAULT;
00597 if (is_whitespace(*it)) {
00598 newprev = ' ';
00599 ++it;
00600 it = find_if(it, end, is_not_whitespace);
00601 if (it == end) break;
00602 }
00603
00604 if ((mode == DEFAULT || mode == IN_GROUP) && value_ranges) {
00605
00606
00607
00608
00609 Utf8Iterator p = it;
00610 unsigned ch = 0;
00611 while (p != end) {
00612 if (ch == '.' && *p == '.') {
00613 ++p;
00614 if (p == end || *p <= ' ' || *p == ')') break;
00615
00616 string r;
00617 do {
00618 Unicode::append_utf8(r, *it++);
00619 } while (it != p);
00620
00621 r.resize(r.size() - 2);
00622 Parse(pParser, RANGE_START, new Term(r), &state);
00623 r.resize(0);
00624
00625
00626 do {
00627 Unicode::append_utf8(r, *p++);
00628 } while (p != end && *p > ' ' && *p != ')');
00629 Parse(pParser, RANGE_END, new Term(r), &state);
00630 it = p;
00631 goto main_lex_loop;
00632 }
00633 ch = *p;
00634 if (!(is_wordchar(ch) || is_currency(ch) ||
00635 (ch < 128 && strchr("%,-./:@", ch)))) break;
00636 ++p;
00637 }
00638 }
00639
00640 if (!is_wordchar(*it)) {
00641 unsigned prev = newprev;
00642 unsigned ch = *it++;
00643 newprev = ch;
00644
00645 if (mode == IN_GROUP) mode = DEFAULT;
00646 switch (ch) {
00647 case '"':
00648 if (mode == DEFAULT) {
00649
00650 it = find_if(it, end, is_not_whitespace);
00651 if (it == end) {
00652
00653
00654
00655 goto done;
00656 }
00657 if (*it == '"') {
00658
00659
00660
00661 newprev = *it++;
00662 break;
00663 }
00664 }
00665 if (flags & QueryParser::FLAG_PHRASE) {
00666 Parse(pParser, QUOTE, NULL, &state);
00667 if (mode == DEFAULT) {
00668 mode = IN_QUOTES;
00669 } else {
00670
00671 if (mode == IN_PREFIXED_QUOTES)
00672 prefix_stack.pop_back();
00673 mode = DEFAULT;
00674 }
00675 }
00676 break;
00677
00678 case '+': case '-':
00679
00680 if (it == end) goto done;
00681 if (prev > ' ' && prev != '(') {
00682
00683 break;
00684 }
00685 if (is_whitespace(*it) || *it == '+' || *it == '-') {
00686
00687
00688
00689 newprev = *it++;
00690 break;
00691 }
00692 if (mode == DEFAULT && (flags & FLAG_LOVEHATE)) {
00693 Parse(pParser, (ch == '+' ? LOVE : HATE), NULL, &state);
00694 goto just_had_operator;
00695 }
00696
00697
00698 break;
00699
00700 case '(':
00701
00702 it = find_if(it, end, is_not_whitespace);
00703
00704 if (it == end) goto done;
00705 if (prev > ' ' && strchr("()+-", prev) == NULL) {
00706
00707 break;
00708 }
00709 if (*it == ')') {
00710
00711 newprev = *it++;
00712 break;
00713 }
00714 if (mode == DEFAULT && (flags & FLAG_BOOLEAN)) {
00715 prefix_stack.push_back(prefix_stack.back());
00716 Parse(pParser, BRA, NULL, &state);
00717 }
00718 break;
00719
00720 case ')':
00721 if (mode == DEFAULT && (flags & FLAG_BOOLEAN)) {
00722
00723
00724
00725 if (prefix_stack.size() > 1) prefix_stack.pop_back();
00726 Parse(pParser, KET, NULL, &state);
00727 }
00728 break;
00729
00730 case '~':
00731
00732 if (it == end) goto done;
00733 if (prev > ' ' && prev != '+' && prev != '-' && prev != '(') {
00734
00735 break;
00736 }
00737 if (!is_wordchar(*it)) {
00738
00739 break;
00740 }
00741 if (mode == DEFAULT && (flags & FLAG_SYNONYM)) {
00742 Parse(pParser, SYNONYM, NULL, &state);
00743 goto just_had_operator;
00744 }
00745 break;
00746 }
00747
00748 continue;
00749 }
00750
00751 Assert(is_wordchar(*it));
00752
00753 size_t term_start_index = it.raw() - qs.data();
00754
00755 newprev = 'A';
00756
00757
00758 const PrefixInfo * prefixinfo = NULL;
00759 if ((mode == DEFAULT || mode == IN_GROUP) && !prefixmap.empty()) {
00760
00761 Utf8Iterator p = find_if(it, end, is_not_wordchar);
00762 if (p != end && *p == ':' && ++p != end && *p > ' ' && *p != ')') {
00763 string field;
00764 p = it;
00765 while (*p != ':')
00766 Unicode::append_utf8(field, *p++);
00767 map<string, PrefixInfo>::const_iterator f;
00768 f = prefixmap.find(field);
00769 if (f != prefixmap.end()) {
00770
00771
00772 unsigned ch = *++p;
00773 prefixinfo = &(f->second);
00774
00775 if (prefixinfo->filter) {
00776
00777 mode = DEFAULT;
00778
00779
00780
00781
00782 it = p;
00783 string name;
00784 while (it != end && *it > ' ' && *it != ')')
00785 Unicode::append_utf8(name, *it++);
00786
00787 field += ':';
00788 field += name;
00789 const list<string> & prefixes = prefixinfo->prefixes;
00790 Term * token = new Term(&state, name, prefixes, field);
00791 Parse(pParser, BOOLEAN_FILTER, token, &state);
00792 continue;
00793 }
00794
00795 if (ch == '"' && (flags & FLAG_PHRASE)) {
00796
00797 mode = IN_PREFIXED_QUOTES;
00798 Parse(pParser, QUOTE, NULL, &state);
00799 it = p;
00800 newprev = ch;
00801 ++it;
00802 prefix_stack.push_back(prefixinfo);
00803 continue;
00804 }
00805
00806 if (ch == '(' && (flags & FLAG_BOOLEAN)) {
00807
00808 mode = DEFAULT;
00809 Parse(pParser, BRA, NULL, &state);
00810 it = p;
00811 newprev = ch;
00812 ++it;
00813 prefix_stack.push_back(prefixinfo);
00814 continue;
00815 }
00816
00817 if (is_wordchar(ch)) {
00818
00819 it = p;
00820 } else {
00821
00822
00823 prefixinfo = NULL;
00824 }
00825 }
00826 }
00827 }
00828
00829 phrased_term:
00830 bool was_acronym;
00831 string term = parse_term(it, end, was_acronym);
00832
00833
00834 if ((mode == DEFAULT || mode == IN_GROUP) &&
00835 (flags & FLAG_BOOLEAN) &&
00836
00837 !was_acronym &&
00838 !prefixinfo &&
00839 term.size() >= 2 && term.size() <= 4 && U_isalpha(term[0])) {
00840
00841 string op = term;
00842 if (flags & FLAG_BOOLEAN_ANY_CASE) {
00843 for (string::iterator i = op.begin(); i != op.end(); ++i) {
00844 *i = C_toupper(*i);
00845 }
00846 }
00847 if (op.size() == 3) {
00848 if (op == "AND") {
00849 Parse(pParser, AND, NULL, &state);
00850 goto just_had_operator;
00851 }
00852 if (op == "NOT") {
00853 Parse(pParser, NOT, NULL, &state);
00854 goto just_had_operator;
00855 }
00856 if (op == "XOR") {
00857 Parse(pParser, XOR, NULL, &state);
00858 goto just_had_operator;
00859 }
00860 if (op == "ADJ") {
00861 if (it != end && *it == '/') {
00862 size_t width = 0;
00863 Utf8Iterator p = it;
00864 while (++p != end && U_isdigit(*p)) {
00865 width = (width * 10) + (*p - '0');
00866 }
00867 if (width && (p == end || is_whitespace(*p))) {
00868 it = p;
00869 Parse(pParser, ADJ, new Term(width), &state);
00870 goto just_had_operator;
00871 }
00872 }
00873
00874 Parse(pParser, ADJ, NULL, &state);
00875 goto just_had_operator;
00876 }
00877 } else if (op.size() == 2) {
00878 if (op == "OR") {
00879 Parse(pParser, OR, NULL, &state);
00880 goto just_had_operator;
00881 }
00882 } else if (op.size() == 4) {
00883 if (op == "NEAR") {
00884 if (it != end && *it == '/') {
00885 size_t width = 0;
00886 Utf8Iterator p = it;
00887 while (++p != end && U_isdigit(*p)) {
00888 width = (width * 10) + (*p - '0');
00889 }
00890 if (width && (p == end || is_whitespace(*p))) {
00891 it = p;
00892 Parse(pParser, NEAR, new Term(width), &state);
00893 goto just_had_operator;
00894 }
00895 }
00896
00897 Parse(pParser, NEAR, NULL, &state);
00898 goto just_had_operator;
00899 }
00900 }
00901 }
00902
00903
00904 if (!prefixinfo) prefixinfo = prefix_stack.back();
00905
00906 Assert(!prefixinfo->filter);
00907
00908 {
00909 string unstemmed_term(term);
00910 term = Unicode::tolower(term);
00911
00912
00913
00914 stem_strategy stem_term = stem_action;
00915 if (stem_term != STEM_NONE) {
00916 if (!stemmer.internal.get()) {
00917
00918 stem_term = STEM_NONE;
00919 } else if (stem_term == STEM_SOME) {
00920 if (!should_stem(unstemmed_term) ||
00921 (it != end && is_stem_preventer(*it))) {
00922
00923 stem_term = STEM_NONE;
00924 }
00925 }
00926 }
00927
00928 Term * term_obj = new Term(&state, term, prefixinfo->prefixes,
00929 unstemmed_term, stem_term, term_pos++);
00930
00931
00932
00933 if ((flags & FLAG_SPELLING_CORRECTION) && !was_acronym) {
00934 list<string>::const_iterator prefixiter;
00935 for (prefixiter = prefixinfo->prefixes.begin();
00936 prefixiter != prefixinfo->prefixes.end();
00937 ++prefixiter) {
00938 if (!prefixiter->empty())
00939 continue;
00940 if (!db.term_exists(term)) {
00941 string suggestion = db.get_spelling_suggestion(term);
00942 if (!suggestion.empty()) {
00943 if (corrected_query.empty()) corrected_query = qs;
00944 size_t term_end_index = it.raw() - qs.data();
00945 size_t n = term_end_index - term_start_index;
00946 size_t pos = term_start_index + correction_offset;
00947 corrected_query.replace(pos, n, suggestion);
00948 correction_offset += suggestion.size();
00949 correction_offset -= n;
00950 }
00951 }
00952 break;
00953 }
00954 }
00955
00956 if (mode == IN_PHRASED_TERM) {
00957 Parse(pParser, PHR_TERM, term_obj, &state);
00958 } else {
00959 if (mode == DEFAULT || mode == IN_GROUP) {
00960 if (it != end) {
00961 if ((flags & FLAG_WILDCARD) && *it == '*') {
00962 Utf8Iterator p(it);
00963 ++p;
00964 if (p == end || !is_wordchar(*p)) {
00965 it = p;
00966
00967
00968 Parse(pParser, WILD_TERM, term_obj, &state);
00969 continue;
00970 }
00971 }
00972 } else {
00973 if (flags & FLAG_PARTIAL) {
00974
00975
00976 Parse(pParser, PARTIAL_TERM, term_obj, &state);
00977 continue;
00978 }
00979 }
00980 }
00981
00982
00983
00984 if (mode == IN_GROUP && is_phrase_generator(*it)) {
00985
00986 Utf8Iterator p = it;
00987 do {
00988 ++p;
00989 } while (p != end && is_phrase_generator(*p));
00990
00991
00992 if (p != end && is_wordchar(*p)) {
00993 mode = DEFAULT;
00994 }
00995 }
00996
00997 Parse(pParser, (mode == IN_GROUP ? GROUP_TERM : TERM),
00998 term_obj, &state);
00999 if (mode != DEFAULT && mode != IN_GROUP) continue;
01000 }
01001 }
01002
01003 if (it == end) break;
01004
01005 if (is_phrase_generator(*it)) {
01006
01007 do {
01008 ++it;
01009 } while (it != end && is_phrase_generator(*it));
01010
01011
01012 if (it != end && is_wordchar(*it)) {
01013 mode = IN_PHRASED_TERM;
01014 term_start_index = it.raw() - qs.data();
01015 goto phrased_term;
01016 }
01017 } else if (mode == DEFAULT || mode == IN_GROUP) {
01018 mode = DEFAULT;
01019 if (!last_was_operator && is_whitespace(*it)) {
01020 newprev = ' ';
01021
01022 do {
01023 ++it;
01024 } while (it != end && is_whitespace(*it));
01025
01026
01027 if (it != end && is_wordchar(*it)) {
01028 mode = IN_GROUP;
01029 }
01030 }
01031 }
01032 }
01033 done:
01034 if (!state.error) {
01035
01036 if (mode == IN_QUOTES || mode == IN_PREFIXED_QUOTES)
01037 Parse(pParser, QUOTE, NULL, &state);
01038 Parse(pParser, 0, NULL, &state);
01039 }
01040 ParseFree(pParser);
01041
01042 errmsg = state.error;
01043 return state.query;
01044 }
01045
01046 struct ProbQuery {
01047 Query * query;
01048 Query * love;
01049 Query * hate;
01050
01051
01052
01053 map<filter_group_id, Query> filter;
01054
01055 ProbQuery() : query(0), love(0), hate(0) { }
01056 ~ProbQuery() {
01057 delete query;
01058 delete love;
01059 delete hate;
01060 }
01061
01062 Query merge_filters() const {
01063 map<filter_group_id, Query>::const_iterator i = filter.begin();
01064 Assert(i != filter.end());
01065 Query q = i->second;
01066 while (++i != filter.end()) {
01067 q = Query(Query::OP_AND, q, i->second);
01068 }
01069 return q;
01070 }
01071 };
01072
01073 class TermGroup {
01074 vector<Term *> terms;
01075
01076 public:
01077 TermGroup() { }
01078
01080 void add_term(Term * term) {
01081 terms.push_back(term);
01082 }
01083
01085 Query * as_group(State *state) const;
01086
01090 void destroy() { delete this; }
01091
01092 protected:
01096 ~TermGroup() {
01097 vector<Term*>::const_iterator i;
01098 for (i = terms.begin(); i != terms.end(); ++i) {
01099 delete *i;
01100 }
01101 }
01102 };
01103
01104 Query *
01105 TermGroup::as_group(State *state) const
01106 {
01107 Query::op default_op = state->default_op();
01108 vector<Query> subqs;
01109 subqs.reserve(terms.size());
01110 if (state->flags & QueryParser::FLAG_AUTO_MULTIWORD_SYNONYMS) {
01111
01112 Database db = state->get_database();
01113
01114 string key;
01115 vector<Term*>::const_iterator begin = terms.begin();
01116 vector<Term*>::const_iterator i = begin;
01117 while (i != terms.end()) {
01118 TermIterator synkey(db.synonym_keys_begin((*i)->name));
01119 TermIterator synend(db.synonym_keys_end((*i)->name));
01120 if (synkey == synend) {
01121
01122 if (state->is_stopword(*i)) {
01123 state->add_to_stoplist(*i);
01124 } else {
01125 subqs.push_back((*i)->get_query_with_auto_synonyms());
01126 }
01127 begin = ++i;
01128 continue;
01129 }
01130 key.resize(0);
01131 while (i != terms.end()) {
01132 if (!key.empty()) key += ' ';
01133 key += (*i)->name;
01134 ++i;
01135 synkey.skip_to(key);
01136 if (synkey == synend || !startswith(*synkey, key)) break;
01137 }
01138
01139 TermIterator syn, end;
01140 while (true) {
01141 syn = db.synonyms_begin(key);
01142 end = db.synonyms_end(key);
01143 if (syn != end) break;
01144 if (--i == begin) break;
01145 key.resize(key.size() - (*i)->name.size() - 1);
01146 }
01147 if (i == begin) {
01148
01149 if (state->is_stopword(*i)) {
01150 state->add_to_stoplist(*i);
01151 } else {
01152 subqs.push_back((*i)->get_query_with_auto_synonyms());
01153 }
01154 begin = ++i;
01155 continue;
01156 }
01157
01158 vector<Query> subqs2;
01159 vector<Term*>::const_iterator j;
01160 for (j = begin; j != i; ++j) {
01161 if (state->is_stopword(*j)) {
01162 state->add_to_stoplist(*j);
01163 } else {
01164 subqs2.push_back((*j)->get_query());
01165 }
01166 }
01167 Query q_original_terms(default_op, subqs2.begin(), subqs2.end());
01168 subqs2.clear();
01169
01170
01171 Xapian::termpos pos = (*begin)->pos;
01172 begin = i;
01173 while (syn != end) {
01174 subqs2.push_back(Query(*syn, 1, pos));
01175 ++syn;
01176 }
01177 Query q_synonym_terms(Query::OP_OR, subqs2.begin(), subqs2.end());
01178 subqs2.clear();
01179 subqs.push_back(Query(Query::OP_OR,
01180 q_original_terms, q_synonym_terms));
01181 }
01182 } else {
01183 vector<Term*>::const_iterator i;
01184 for (i = terms.begin(); i != terms.end(); ++i) {
01185 if (state->is_stopword(*i)) {
01186 state->add_to_stoplist(*i);
01187 } else {
01188 subqs.push_back((*i)->get_query_with_auto_synonyms());
01189 }
01190 }
01191 }
01192 delete this;
01193 return new Query(default_op, subqs.begin(), subqs.end());
01194 }
01195
01196 class TermList {
01197 vector<Term *> terms;
01198 size_t window;
01199
01209 bool uniform_prefixes;
01210
01214 list<string> prefixes;
01215
01216 public:
01217 TermList() : window(0), uniform_prefixes(true) { }
01218
01220 void add_positional_term(Term * term) {
01221 if (terms.empty()) {
01222 prefixes = term->prefixes;
01223 } else if (uniform_prefixes && prefixes != term->prefixes) {
01224 prefixes.clear();
01225 uniform_prefixes = false;
01226 }
01227 term->need_positions();
01228 terms.push_back(term);
01229 }
01230
01231 void adjust_window(size_t alternative_window) {
01232 if (alternative_window > window) window = alternative_window;
01233 }
01234
01236 Query * as_opwindow_query(Query::op op, Xapian::termcount w_delta) const {
01237 Query * q = NULL;
01238 size_t n_terms = terms.size();
01239 Xapian::termcount w = w_delta + terms.size();
01240 if (uniform_prefixes) {
01241 list<string>::const_iterator piter;
01242 for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
01243 vector<Query> subqs;
01244 subqs.reserve(n_terms);
01245 vector<Term *>::const_iterator titer;
01246 for (titer = terms.begin(); titer != terms.end(); ++titer) {
01247 Term * t = *titer;
01248 subqs.push_back(Query(t->make_term(*piter), 1, t->pos));
01249 }
01250 add_to_query(q, Query::OP_OR,
01251 Query(op, subqs.begin(), subqs.end(), w));
01252 }
01253 } else {
01254 vector<Query> subqs;
01255 subqs.reserve(n_terms);
01256 vector<Term *>::const_iterator titer;
01257 for (titer = terms.begin(); titer != terms.end(); ++titer) {
01258 subqs.push_back((*titer)->get_query());
01259 }
01260 q = new Query(op, subqs.begin(), subqs.end(), w);
01261 }
01262
01263 delete this;
01264 return q;
01265 }
01266
01268 Query * as_phrase_query() const {
01269 return as_opwindow_query(Query::OP_PHRASE, 0);
01270 }
01271
01273 Query * as_near_query() const {
01274
01275
01276
01277 size_t w = window;
01278 if (w == 0) w = 10;
01279 return as_opwindow_query(Query::OP_NEAR, w - 1);
01280 }
01281
01283 Query * as_adj_query() const {
01284
01285
01286
01287 size_t w = window;
01288 if (w == 0) w = 10;
01289 return as_opwindow_query(Query::OP_PHRASE, w - 1);
01290 }
01291
01295 void destroy() { delete this; }
01296
01297 protected:
01301 ~TermList() {
01302 vector<Term *>::const_iterator t;
01303 for (t = terms.begin(); t != terms.end(); ++t) {
01304 delete *t;
01305 }
01306 }
01307 };
01308
01309
01310 #define BOOL_OP_TO_QUERY(E, A, OP, B, OP_TXT) \
01311 do {\
01312 if (!A || !B) {\
01313 state->error = "Syntax: <expression> "OP_TXT" <expression>";\
01314 yy_parse_failed(yypParser);\
01315 return;\
01316 }\
01317 E = new Query(OP, *A, *B);\
01318 delete A;\
01319 delete B;\
01320 } while (0)
01321
01322 #line 1324 "queryparser/queryparser_internal.cc"
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335 #ifndef INTERFACE
01336 # define INTERFACE 1
01337 #endif
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371 #define YYCODETYPE unsigned char
01372 #define YYNOCODE 38
01373 #define YYACTIONTYPE unsigned char
01374 #define ParseTOKENTYPE Term *
01375 typedef union {
01376 ParseTOKENTYPE yy0;
01377 TermList * yy1;
01378 int yy8;
01379 ProbQuery * yy9;
01380 Query * yy13;
01381 TermGroup * yy60;
01382 int yy75;
01383 } YYMINORTYPE;
01384 #define YYSTACKDEPTH 100
01385 #define ParseARG_SDECL State * state;
01386 #define ParseARG_PDECL ,State * state
01387 #define ParseARG_FETCH State * state = yypParser->state
01388 #define ParseARG_STORE yypParser->state = state
01389 #define YYNSTATE 73
01390 #define YYNRULE 51
01391 #define YYERRORSYMBOL 22
01392 #define YYERRSYMDT yy75
01393 #define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
01394 #define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
01395 #define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444 static const YYACTIONTYPE yy_action[] = {
01445 125, 1, 2, 3, 13, 43, 46, 60, 70, 73,
01446 30, 32, 34, 37, 12, 2, 5, 13, 43, 46,
01447 60, 70, 19, 30, 32, 34, 37, 12, 2, 7,
01448 13, 43, 46, 60, 70, 21, 30, 32, 34, 37,
01449 12, 2, 9, 13, 43, 46, 60, 70, 29, 30,
01450 32, 34, 37, 12, 2, 11, 13, 43, 46, 60,
01451 70, 31, 30, 32, 34, 37, 41, 2, 3, 13,
01452 43, 46, 60, 70, 33, 30, 32, 34, 37, 12,
01453 2, 72, 13, 43, 46, 60, 70, 74, 30, 32,
01454 34, 37, 10, 4, 6, 62, 65, 54, 69, 4,
01455 6, 23, 24, 68, 44, 26, 25, 40, 71, 36,
01456 35, 62, 65, 54, 69, 38, 28, 23, 24, 68,
01457 44, 39, 25, 40, 27, 45, 62, 65, 54, 69,
01458 42, 48, 23, 24, 68, 44, 55, 25, 40, 90,
01459 90, 99, 99, 54, 15, 90, 90, 23, 24, 99,
01460 99, 90, 25, 40, 103, 90, 103, 103, 103, 103,
01461 18, 20, 8, 10, 4, 6, 17, 16, 54, 52,
01462 90, 90, 23, 24, 51, 103, 90, 25, 40, 54,
01463 52, 90, 90, 23, 24, 58, 54, 52, 25, 40,
01464 23, 24, 64, 90, 90, 25, 40, 54, 52, 90,
01465 90, 23, 24, 67, 90, 90, 25, 40, 14, 22,
01466 90, 30, 32, 34, 37, 90, 50, 90, 90, 53,
01467 90, 30, 32, 34, 37, 57, 90, 90, 53, 90,
01468 30, 32, 34, 37, 54, 15, 90, 90, 23, 24,
01469 90, 90, 90, 25, 40, 61, 22, 90, 30, 32,
01470 34, 37, 90, 63, 90, 90, 53, 90, 30, 32,
01471 34, 37, 66, 90, 90, 53, 90, 30, 32, 34,
01472 37, 104, 90, 104, 104, 104, 104, 90, 18, 20,
01473 90, 90, 49, 56, 17, 16, 90, 90, 90, 90,
01474 59, 47, 104,
01475 };
01476 static const YYCODETYPE yy_lookahead[] = {
01477 23, 24, 25, 26, 27, 28, 29, 30, 31, 0,
01478 33, 34, 35, 36, 24, 25, 26, 27, 28, 29,
01479 30, 31, 11, 33, 34, 35, 36, 24, 25, 26,
01480 27, 28, 29, 30, 31, 11, 33, 34, 35, 36,
01481 24, 25, 26, 27, 28, 29, 30, 31, 11, 33,
01482 34, 35, 36, 24, 25, 26, 27, 28, 29, 30,
01483 31, 13, 33, 34, 35, 36, 24, 25, 26, 27,
01484 28, 29, 30, 31, 12, 33, 34, 35, 36, 24,
01485 25, 26, 27, 28, 29, 30, 31, 0, 33, 34,
01486 35, 36, 3, 4, 5, 8, 9, 10, 11, 4,
01487 5, 14, 15, 16, 17, 32, 19, 20, 5, 11,
01488 6, 8, 9, 10, 11, 7, 11, 14, 15, 16,
01489 17, 11, 19, 20, 19, 18, 8, 9, 10, 11,
01490 21, 18, 14, 15, 16, 17, 11, 19, 20, 37,
01491 37, 8, 9, 10, 11, 37, 37, 14, 15, 16,
01492 17, 37, 19, 20, 0, 37, 2, 3, 4, 5,
01493 6, 7, 2, 3, 4, 5, 12, 13, 10, 11,
01494 37, 37, 14, 15, 16, 21, 37, 19, 20, 10,
01495 11, 37, 37, 14, 15, 16, 10, 11, 19, 20,
01496 14, 15, 16, 37, 37, 19, 20, 10, 11, 37,
01497 37, 14, 15, 16, 37, 37, 19, 20, 30, 31,
01498 37, 33, 34, 35, 36, 37, 28, 37, 37, 31,
01499 37, 33, 34, 35, 36, 28, 37, 37, 31, 37,
01500 33, 34, 35, 36, 10, 11, 37, 37, 14, 15,
01501 37, 37, 37, 19, 20, 30, 31, 37, 33, 34,
01502 35, 36, 37, 28, 37, 37, 31, 37, 33, 34,
01503 35, 36, 28, 37, 37, 31, 37, 33, 34, 35,
01504 36, 0, 37, 2, 3, 4, 5, 37, 6, 7,
01505 37, 37, 8, 9, 12, 13, 37, 37, 37, 37,
01506 16, 17, 21,
01507 };
01508 #define YY_SHIFT_USE_DFLT (-1)
01509 static const short yy_shift_ofst[] = {
01510 87, 9, -1, 160, 103, -1, 118, -1, 118, 89,
01511 118, 95, -1, 133, -1, 272, -1, -1, 11, -1,
01512 24, -1, -1, -1, -1, 37, 105, -1, -1, -1,
01513 48, -1, 62, -1, 104, 98, -1, 108, 110, -1,
01514 118, 109, -1, -1, 107, -1, 274, 113, -1, 158,
01515 -1, -1, 272, -1, 125, -1, 169, -1, -1, -1,
01516 224, -1, 176, -1, -1, 187, -1, -1, -1, 154,
01517 271, 118, -1,
01518 };
01519 #define YY_REDUCE_USE_DFLT (-24)
01520 static const short yy_reduce_ofst[] = {
01521 -23, -24, -24, -24, -10, -24, 3, -24, 16, -24,
01522 29, -24, -24, 178, -24, -24, -24, -24, -24, -24,
01523 -24, -24, -24, -24, -24, 73, -24, -24, -24, -24,
01524 -24, -24, -24, -24, -24, -24, -24, -24, -24, -24,
01525 42, -24, -24, -24, -24, -24, -24, -24, -24, 188,
01526 -24, -24, -24, -24, -24, -24, 197, -24, -24, -24,
01527 215, -24, 225, -24, -24, 234, -24, -24, -24, -24,
01528 -24, 55, -24,
01529 };
01530 static const YYACTIONTYPE yy_default[] = {
01531 82, 81, 75, 124, 82, 76, 82, 77, 82, 79,
01532 82, 80, 81, 83, 88, 101, 116, 118, 124, 120,
01533 124, 122, 102, 105, 106, 124, 124, 107, 115, 114,
01534 108, 117, 109, 119, 110, 124, 121, 111, 124, 123,
01535 82, 81, 112, 84, 124, 85, 124, 124, 86, 124,
01536 90, 98, 103, 104, 124, 113, 124, 92, 94, 96,
01537 100, 87, 124, 89, 97, 124, 91, 93, 95, 101,
01538 102, 82, 78,
01539 };
01540 #define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0]))
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552 #ifdef YYFALLBACK
01553 static const YYCODETYPE yyFallback[] = {
01554 };
01555 #endif
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569 struct yyStackEntry {
01570 yyStackEntry() {
01571 stateno = 0;
01572 major = 0;
01573 }
01574 yyStackEntry(int stateno_, int major_, YYMINORTYPE minor_)
01575 {
01576 stateno = stateno_;
01577 major = major_;
01578 minor = minor_;
01579 }
01580 int stateno;
01581 int major;
01582
01583 YYMINORTYPE minor;
01584
01585 };
01586
01587
01588
01589 struct yyParser {
01590 int yyerrcnt;
01591 ParseARG_SDECL
01592 vector<yyStackEntry> yystack;
01593 };
01594 typedef struct yyParser yyParser;
01595
01596
01597 static void yy_parse_failed(yyParser *);
01598
01599 #include "omdebug.h"
01600
01601 #ifdef XAPIAN_DEBUG_VERBOSE
01602
01603
01604 static const char *const yyTokenName[] = {
01605 "$", "ERROR", "OR", "XOR",
01606 "AND", "NOT", "NEAR", "ADJ",
01607 "LOVE", "HATE", "SYNONYM", "TERM",
01608 "GROUP_TERM", "PHR_TERM", "WILD_TERM", "PARTIAL_TERM",
01609 "BOOLEAN_FILTER", "RANGE_START", "RANGE_END", "QUOTE",
01610 "BRA", "KET", "error", "query",
01611 "expr", "prob_expr", "bool_arg", "prob",
01612 "term", "stop_prob", "stop_term", "compound_term",
01613 "phrase", "phrased_term", "group", "near_expr",
01614 "adj_expr",
01615 };
01616
01617
01618
01619 static const char *const yyRuleName[] = {
01620 "query ::= expr",
01621 "query ::=",
01622 "expr ::= prob_expr",
01623 "expr ::= bool_arg AND bool_arg",
01624 "expr ::= bool_arg NOT bool_arg",
01625 "expr ::= bool_arg AND NOT bool_arg",
01626 "expr ::= bool_arg OR bool_arg",
01627 "expr ::= bool_arg XOR bool_arg",
01628 "bool_arg ::= expr",
01629 "bool_arg ::=",
01630 "prob_expr ::= prob",
01631 "prob_expr ::= term",
01632 "prob ::= RANGE_START RANGE_END",
01633 "prob ::= stop_prob RANGE_START RANGE_END",
01634 "prob ::= stop_term stop_term",
01635 "prob ::= prob stop_term",
01636 "prob ::= LOVE term",
01637 "prob ::= stop_prob LOVE term",
01638 "prob ::= HATE term",
01639 "prob ::= stop_prob HATE term",
01640 "prob ::= HATE BOOLEAN_FILTER",
01641 "prob ::= stop_prob HATE BOOLEAN_FILTER",
01642 "prob ::= BOOLEAN_FILTER",
01643 "prob ::= stop_prob BOOLEAN_FILTER",
01644 "prob ::= LOVE BOOLEAN_FILTER",
01645 "prob ::= stop_prob LOVE BOOLEAN_FILTER",
01646 "stop_prob ::= prob",
01647 "stop_prob ::= stop_term",
01648 "stop_term ::= TERM",
01649 "stop_term ::= compound_term",
01650 "term ::= TERM",
01651 "term ::= compound_term",
01652 "compound_term ::= WILD_TERM",
01653 "compound_term ::= PARTIAL_TERM",
01654 "compound_term ::= QUOTE phrase QUOTE",
01655 "compound_term ::= phrased_term",
01656 "compound_term ::= group",
01657 "compound_term ::= near_expr",
01658 "compound_term ::= adj_expr",
01659 "compound_term ::= BRA expr KET",
01660 "compound_term ::= SYNONYM TERM",
01661 "phrase ::= TERM",
01662 "phrase ::= phrase TERM",
01663 "phrased_term ::= TERM PHR_TERM",
01664 "phrased_term ::= phrased_term PHR_TERM",
01665 "group ::= TERM GROUP_TERM",
01666 "group ::= group GROUP_TERM",
01667 "near_expr ::= TERM NEAR TERM",
01668 "near_expr ::= near_expr NEAR TERM",
01669 "adj_expr ::= TERM ADJ TERM",
01670 "adj_expr ::= adj_expr ADJ TERM",
01671 };
01672
01673
01674
01675
01676
01677 static const char *ParseTokenName(int tokenType){
01678 if( tokenType>0 && size_t(tokenType)<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
01679 return yyTokenName[tokenType];
01680 }
01681 return "Unknown";
01682 }
01683
01684
01685
01686
01687
01688 static const char *ParseRuleName(int ruleNum){
01689 if( ruleNum>0 && size_t(ruleNum)<(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
01690 return yyRuleName[ruleNum];
01691 }
01692 return "Unknown";
01693 }
01694 #endif
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708 static yyParser *ParseAlloc(){
01709 return new yyParser;
01710 }
01711
01712
01713
01714
01715
01716
01717 static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
01718 switch( yymajor ){
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729 case 1:
01730 case 2:
01731 case 3:
01732 case 4:
01733 case 5:
01734 case 6:
01735 case 7:
01736 case 8:
01737 case 9:
01738 case 10:
01739 case 11:
01740 case 12:
01741 case 13:
01742 case 14:
01743 case 15:
01744 case 16:
01745 case 17:
01746 case 18:
01747 case 19:
01748 case 20:
01749 case 21:
01750 #line 1319 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
01751 {delete (yypminor->yy0);}
01752 #line 1754 "queryparser/queryparser_internal.cc"
01753 break;
01754 case 24:
01755 case 25:
01756 case 26:
01757 case 28:
01758 case 30:
01759 case 31:
01760 #line 1390 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
01761 {delete (yypminor->yy13);}
01762 #line 1764 "queryparser/queryparser_internal.cc"
01763 break;
01764 case 27:
01765 case 29:
01766 #line 1483 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
01767 {delete (yypminor->yy9);}
01768 #line 1770 "queryparser/queryparser_internal.cc"
01769 break;
01770 case 32:
01771 case 33:
01772 case 35:
01773 case 36:
01774 #line 1684 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
01775 {(yypminor->yy1)->destroy();}
01776 #line 1778 "queryparser/queryparser_internal.cc"
01777 break;
01778 case 34:
01779 #line 1718 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
01780 {(yypminor->yy60)->destroy();}
01781 #line 1783 "queryparser/queryparser_internal.cc"
01782 break;
01783 default: break;
01784 }
01785 }
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795 static int yy_pop_parser_stack(yyParser *pParser){
01796 YYCODETYPE yymajor;
01797 if( pParser->yystack.empty() ) return 0;
01798 yyStackEntry *yytos = &pParser->yystack.back();
01799
01800 DEBUGLINE(QUERYPARSER, "Popping " << ParseTokenName(yytos->major));
01801 yymajor = (YYCODETYPE)yytos->major;
01802 yy_destructor( yymajor, &yytos->minor);
01803 pParser->yystack.pop_back();
01804 return yymajor;
01805 }
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815 static void ParseFree(
01816 yyParser *pParser
01817 ){
01818 if( pParser==0 ) return;
01819 while( !pParser->yystack.empty() ) yy_pop_parser_stack(pParser);
01820 delete pParser;
01821 }
01822
01823
01824
01825
01826
01827
01828
01829
01830
01831 static int yy_find_shift_action(
01832 yyParser *pParser,
01833 int iLookAhead
01834 ){
01835 int i;
01836
01837 int stateno = pParser->yystack.back().stateno;
01838
01839 i = yy_shift_ofst[stateno];
01840 if( i==YY_SHIFT_USE_DFLT ){
01841 return yy_default[stateno];
01842 }
01843 if( iLookAhead==YYNOCODE ){
01844 return YY_NO_ACTION;
01845 }
01846 i += iLookAhead;
01847 if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
01848 #ifdef YYFALLBACK
01849 int iFallback;
01850 if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
01851 && (iFallback = yyFallback[iLookAhead])!=0 ){
01852 DEBUGLINE(QUERYPARSER,
01853 "FALLBACK " << ParseTokenName(iLookAhead) << " => " <<
01854 ParseTokenName(iFallback));
01855 return yy_find_shift_action(pParser, iFallback);
01856 }
01857 #endif
01858 return yy_default[stateno];
01859 }else{
01860 return yy_action[i];
01861 }
01862 }
01863
01864
01865
01866
01867
01868
01869
01870
01871
01872 static int yy_find_reduce_action(
01873 yyParser *pParser,
01874 int iLookAhead
01875 ){
01876 int i;
01877 int stateno = pParser->yystack.back().stateno;
01878
01879 i = yy_reduce_ofst[stateno];
01880 if( i==YY_REDUCE_USE_DFLT ){
01881 return yy_default[stateno];
01882 }
01883 if( iLookAhead==YYNOCODE ){
01884 return YY_NO_ACTION;
01885 }
01886 i += iLookAhead;
01887 if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
01888 return yy_default[stateno];
01889 }else{
01890 return yy_action[i];
01891 }
01892 }
01893
01894
01895
01896
01897 static void yy_shift(
01898 yyParser *yypParser,
01899 int yyNewState,
01900 int yyMajor,
01901 YYMINORTYPE *yypMinor
01902 ){
01903
01904
01905
01906
01907 #if 0
01908 #endif
01909 #ifdef XAPIAN_DEBUG_VERBOSE
01910 unsigned i;
01911 DEBUGLINE(QUERYPARSER, "Shift " << yyNewState);
01912 string stack("Stack:");
01913 for (i = 0; i < yypParser->yystack.size(); i++) {
01914 stack += ' ';
01915 stack += ParseTokenName(yypParser->yystack[i].major);
01916 }
01917 DEBUGLINE(QUERYPARSER, stack);
01918 #endif
01919 yypParser->yystack.push_back(yyStackEntry(yyNewState, yyMajor, *yypMinor));
01920 }
01921
01922
01923
01924
01925 static const struct {
01926 YYCODETYPE lhs;
01927 unsigned char nrhs;
01928 } yyRuleInfo[] = {
01929 { 23, 1 },
01930 { 23, 0 },
01931 { 24, 1 },
01932 { 24, 3 },
01933 { 24, 3 },
01934 { 24, 4 },
01935 { 24, 3 },
01936 { 24, 3 },
01937 { 26, 1 },
01938 { 26, 0 },
01939 { 25, 1 },
01940 { 25, 1 },
01941 { 27, 2 },
01942 { 27, 3 },
01943 { 27, 2 },
01944 { 27, 2 },
01945 { 27, 2 },
01946 { 27, 3 },
01947 { 27, 2 },
01948 { 27, 3 },
01949 { 27, 2 },
01950 { 27, 3 },
01951 { 27, 1 },
01952 { 27, 2 },
01953 { 27, 2 },
01954 { 27, 3 },
01955 { 29, 1 },
01956 { 29, 1 },
01957 { 30, 1 },
01958 { 30, 1 },
01959 { 28, 1 },
01960 { 28, 1 },
01961 { 31, 1 },
01962 { 31, 1 },
01963 { 31, 3 },
01964 { 31, 1 },
01965 { 31, 1 },
01966 { 31, 1 },
01967 { 31, 1 },
01968 { 31, 3 },
01969 { 31, 2 },
01970 { 32, 1 },
01971 { 32, 2 },
01972 { 33, 2 },
01973 { 33, 2 },
01974 { 34, 2 },
01975 { 34, 2 },
01976 { 35, 3 },
01977 { 35, 3 },
01978 { 36, 3 },
01979 { 36, 3 },
01980 };
01981
01982 static void yy_accept(yyParser*);
01983
01984
01985
01986
01987
01988 static void yy_reduce(
01989 yyParser *yypParser,
01990 int yyruleno
01991 ){
01992 int yygoto;
01993 int yyact;
01994 YYMINORTYPE yygotominor;
01995 yyStackEntry *yymsp;
01996 int yysize;
01997 ParseARG_FETCH;
01998 yymsp = &yypParser->yystack.back();
01999 #ifdef XAPIAN_DEBUG_VERBOSE
02000 DEBUGLINE(QUERYPARSER, "Reduce [" << ParseRuleName(yyruleno) << "].");
02001 #endif
02002
02003 switch( yyruleno ){
02004
02005
02006
02007
02008
02009
02010
02011
02012 case 0:
02013 #line 1372 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02014 {
02015
02016 if (yymsp[0].minor.yy13) {
02017 state->query = *yymsp[0].minor.yy13;
02018 delete yymsp[0].minor.yy13;
02019 } else {
02020 state->query = Query();
02021 }
02022 }
02023 #line 2025 "queryparser/queryparser_internal.cc"
02024 break;
02025 case 1:
02026 #line 1382 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02027 {
02028
02029 state->query = Query();
02030 }
02031 #line 2033 "queryparser/queryparser_internal.cc"
02032 break;
02033 case 2:
02034 case 8:
02035 #line 1393 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02036 { yygotominor.yy13 = yymsp[0].minor.yy13; }
02037 #line 2039 "queryparser/queryparser_internal.cc"
02038 break;
02039 case 3:
02040 #line 1396 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02041 { BOOL_OP_TO_QUERY(yygotominor.yy13, yymsp[-2].minor.yy13, Query::OP_AND, yymsp[0].minor.yy13, "AND"); yy_destructor(4,&yymsp[-1].minor);
02042 }
02043 #line 2045 "queryparser/queryparser_internal.cc"
02044 break;
02045 case 4:
02046 #line 1398 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02047 {
02048
02049 if (!yymsp[-2].minor.yy13 && (state->flags & QueryParser::FLAG_PURE_NOT)) {
02050 yymsp[-2].minor.yy13 = new Query("", 1, 0);
02051 }
02052 BOOL_OP_TO_QUERY(yygotominor.yy13, yymsp[-2].minor.yy13, Query::OP_AND_NOT, yymsp[0].minor.yy13, "NOT");
02053 yy_destructor(5,&yymsp[-1].minor);
02054 }
02055 #line 2057 "queryparser/queryparser_internal.cc"
02056 break;
02057 case 5:
02058 #line 1407 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02059 { BOOL_OP_TO_QUERY(yygotominor.yy13, yymsp[-3].minor.yy13, Query::OP_AND_NOT, yymsp[0].minor.yy13, "AND NOT"); yy_destructor(4,&yymsp[-2].minor);
02060 yy_destructor(5,&yymsp[-1].minor);
02061 }
02062 #line 2064 "queryparser/queryparser_internal.cc"
02063 break;
02064 case 6:
02065 #line 1410 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02066 { BOOL_OP_TO_QUERY(yygotominor.yy13, yymsp[-2].minor.yy13, Query::OP_OR, yymsp[0].minor.yy13, "OR"); yy_destructor(2,&yymsp[-1].minor);
02067 }
02068 #line 2070 "queryparser/queryparser_internal.cc"
02069 break;
02070 case 7:
02071 #line 1413 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02072 { BOOL_OP_TO_QUERY(yygotominor.yy13, yymsp[-2].minor.yy13, Query::OP_XOR, yymsp[0].minor.yy13, "XOR"); yy_destructor(3,&yymsp[-1].minor);
02073 }
02074 #line 2076 "queryparser/queryparser_internal.cc"
02075 break;
02076 case 9:
02077 #line 1422 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02078 {
02079
02080
02081
02082 yygotominor.yy13 = NULL;
02083 }
02084 #line 2086 "queryparser/queryparser_internal.cc"
02085 break;
02086 case 10:
02087 #line 1434 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02088 {
02089 yygotominor.yy13 = yymsp[0].minor.yy9->query;
02090 yymsp[0].minor.yy9->query = NULL;
02091
02092 if (yymsp[0].minor.yy9->love) {
02093 if (yymsp[0].minor.yy9->love->empty()) {
02094
02095 delete yygotominor.yy13;
02096 yygotominor.yy13 = yymsp[0].minor.yy9->love;
02097 } else if (yygotominor.yy13) {
02098 swap(yygotominor.yy13, yymsp[0].minor.yy9->love);
02099 add_to_query(yygotominor.yy13, Query::OP_AND_MAYBE, yymsp[0].minor.yy9->love);
02100 } else {
02101 yygotominor.yy13 = yymsp[0].minor.yy9->love;
02102 }
02103 yymsp[0].minor.yy9->love = NULL;
02104 }
02105
02106 if (!yymsp[0].minor.yy9->filter.empty()) {
02107 if (yygotominor.yy13) {
02108 add_to_query(yygotominor.yy13, Query::OP_FILTER, yymsp[0].minor.yy9->merge_filters());
02109 } else {
02110
02111 yygotominor.yy13 = new Query(Query::OP_SCALE_WEIGHT, yymsp[0].minor.yy9->merge_filters(), 0.0);
02112 }
02113 }
02114
02115 if (yymsp[0].minor.yy9->hate && !yymsp[0].minor.yy9->hate->empty()) {
02116 if (!yygotominor.yy13) {
02117
02118 yy_parse_failed(yypParser);
02119 return;
02120 }
02121 *yygotominor.yy13 = Query(Query::OP_AND_NOT, *yygotominor.yy13, *yymsp[0].minor.yy9->hate);
02122 }
02123
02124 delete yymsp[0].minor.yy9;
02125 }
02126 #line 2128 "queryparser/queryparser_internal.cc"
02127 break;
02128 case 11:
02129 case 29:
02130 case 31:
02131 #line 1473 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02132 {
02133 yygotominor.yy13 = yymsp[0].minor.yy13;
02134 }
02135 #line 2137 "queryparser/queryparser_internal.cc"
02136 break;
02137 case 12:
02138 #line 1485 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02139 {
02140 Query range;
02141 Xapian::valueno valno = state->value_range(range, yymsp[-1].minor.yy0, yymsp[0].minor.yy0);
02142 if (valno == BAD_VALUENO) {
02143 yy_parse_failed(yypParser);
02144 return;
02145 }
02146 yygotominor.yy9 = new ProbQuery;
02147 yygotominor.yy9->filter[filter_group_id(valno)] = range;
02148 }
02149 #line 2151 "queryparser/queryparser_internal.cc"
02150 break;
02151 case 13:
02152 #line 1496 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02153 {
02154 Query range;
02155 Xapian::valueno valno = state->value_range(range, yymsp[-1].minor.yy0, yymsp[0].minor.yy0);
02156 if (valno == BAD_VALUENO) {
02157 yy_parse_failed(yypParser);
02158 return;
02159 }
02160 yygotominor.yy9 = yymsp[-2].minor.yy9;
02161 Query & q = yygotominor.yy9->filter[filter_group_id(valno)];
02162 q = Query(Query::OP_OR, q, range);
02163 }
02164 #line 2166 "queryparser/queryparser_internal.cc"
02165 break;
02166 case 14:
02167 #line 1508 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02168 {
02169 yygotominor.yy9 = new ProbQuery;
02170 yygotominor.yy9->query = yymsp[-1].minor.yy13;
02171 if (yymsp[0].minor.yy13) add_to_query(yygotominor.yy9->query, state->default_op(), yymsp[0].minor.yy13);
02172 }
02173 #line 2175 "queryparser/queryparser_internal.cc"
02174 break;
02175 case 15:
02176 #line 1514 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02177 {
02178 yygotominor.yy9 = yymsp[-1].minor.yy9;
02179
02180 if (yymsp[0].minor.yy13) add_to_query(yygotominor.yy9->query, state->default_op(), yymsp[0].minor.yy13);
02181 }
02182 #line 2184 "queryparser/queryparser_internal.cc"
02183 break;
02184 case 16:
02185 #line 1520 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02186 {
02187 yygotominor.yy9 = new ProbQuery;
02188 if (state->default_op() == Query::OP_AND) {
02189 yygotominor.yy9->query = yymsp[0].minor.yy13;
02190 } else {
02191 yygotominor.yy9->love = yymsp[0].minor.yy13;
02192 }
02193 yy_destructor(8,&yymsp[-1].minor);
02194 }
02195 #line 2197 "queryparser/queryparser_internal.cc"
02196 break;
02197 case 17:
02198 #line 1529 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02199 {
02200 yygotominor.yy9 = yymsp[-2].minor.yy9;
02201 if (state->default_op() == Query::OP_AND) {
02202
02203
02204
02205 add_to_query(yygotominor.yy9->query, Query::OP_AND, yymsp[0].minor.yy13);
02206 } else {
02207 add_to_query(yygotominor.yy9->love, Query::OP_AND, yymsp[0].minor.yy13);
02208 }
02209 yy_destructor(8,&yymsp[-1].minor);
02210 }
02211 #line 2213 "queryparser/queryparser_internal.cc"
02212 break;
02213 case 18:
02214 #line 1541 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02215 {
02216 yygotominor.yy9 = new ProbQuery;
02217 yygotominor.yy9->hate = yymsp[0].minor.yy13;
02218 yy_destructor(9,&yymsp[-1].minor);
02219 }
02220 #line 2222 "queryparser/queryparser_internal.cc"
02221 break;
02222 case 19:
02223 #line 1546 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02224 {
02225 yygotominor.yy9 = yymsp[-2].minor.yy9;
02226 add_to_query(yygotominor.yy9->hate, Query::OP_OR, yymsp[0].minor.yy13);
02227 yy_destructor(9,&yymsp[-1].minor);
02228 }
02229 #line 2231 "queryparser/queryparser_internal.cc"
02230 break;
02231 case 20:
02232 #line 1551 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02233 {
02234 yygotominor.yy9 = new ProbQuery;
02235 yygotominor.yy9->hate = new Query(yymsp[0].minor.yy0->get_query());
02236 delete yymsp[0].minor.yy0;
02237 yy_destructor(9,&yymsp[-1].minor);
02238 }
02239 #line 2241 "queryparser/queryparser_internal.cc"
02240 break;
02241 case 21:
02242 #line 1557 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02243 {
02244 yygotominor.yy9 = yymsp[-2].minor.yy9;
02245 add_to_query(yygotominor.yy9->hate, Query::OP_OR, yymsp[0].minor.yy0->get_query());
02246 delete yymsp[0].minor.yy0;
02247 yy_destructor(9,&yymsp[-1].minor);
02248 }
02249 #line 2251 "queryparser/queryparser_internal.cc"
02250 break;
02251 case 22:
02252 #line 1563 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02253 {
02254 yygotominor.yy9 = new ProbQuery;
02255 yygotominor.yy9->filter[yymsp[0].minor.yy0->get_filter_group_id()] = yymsp[0].minor.yy0->get_query();
02256 delete yymsp[0].minor.yy0;
02257 }
02258 #line 2260 "queryparser/queryparser_internal.cc"
02259 break;
02260 case 23:
02261 #line 1569 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02262 {
02263 yygotominor.yy9 = yymsp[-1].minor.yy9;
02264
02265 Query & q = yygotominor.yy9->filter[yymsp[0].minor.yy0->get_filter_group_id()];
02266 q = Query(Query::OP_OR, q, yymsp[0].minor.yy0->get_query());
02267 delete yymsp[0].minor.yy0;
02268 }
02269 #line 2271 "queryparser/queryparser_internal.cc"
02270 break;
02271 case 24:
02272 #line 1577 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02273 {
02274
02275 yygotominor.yy9 = new ProbQuery;
02276 yygotominor.yy9->filter[yymsp[0].minor.yy0->get_filter_group_id()] = yymsp[0].minor.yy0->get_query();
02277 delete yymsp[0].minor.yy0;
02278 yy_destructor(8,&yymsp[-1].minor);
02279 }
02280 #line 2282 "queryparser/queryparser_internal.cc"
02281 break;
02282 case 25:
02283 #line 1584 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02284 {
02285
02286 yygotominor.yy9 = yymsp[-2].minor.yy9;
02287
02288 Query & q = yygotominor.yy9->filter[yymsp[0].minor.yy0->get_filter_group_id()];
02289 q = Query(Query::OP_OR, q, yymsp[0].minor.yy0->get_query());
02290 delete yymsp[0].minor.yy0;
02291 yy_destructor(8,&yymsp[-1].minor);
02292 }
02293 #line 2295 "queryparser/queryparser_internal.cc"
02294 break;
02295 case 26:
02296 #line 1599 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02297 { yygotominor.yy9 = yymsp[0].minor.yy9; }
02298 #line 2300 "queryparser/queryparser_internal.cc"
02299 break;
02300 case 27:
02301 #line 1601 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02302 {
02303 yygotominor.yy9 = new ProbQuery;
02304 yygotominor.yy9->query = yymsp[0].minor.yy13;
02305 }
02306 #line 2308 "queryparser/queryparser_internal.cc"
02307 break;
02308 case 28:
02309 #line 1615 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02310 {
02311 if (state->is_stopword(yymsp[0].minor.yy0)) {
02312 yygotominor.yy13 = NULL;
02313 state->add_to_stoplist(yymsp[0].minor.yy0);
02314 } else {
02315 yygotominor.yy13 = new Query(yymsp[0].minor.yy0->get_query_with_auto_synonyms());
02316 }
02317 delete yymsp[0].minor.yy0;
02318 }
02319 #line 2321 "queryparser/queryparser_internal.cc"
02320 break;
02321 case 30:
02322 #line 1634 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02323 {
02324 yygotominor.yy13 = new Query(yymsp[0].minor.yy0->get_query_with_auto_synonyms());
02325 delete yymsp[0].minor.yy0;
02326 }
02327 #line 2329 "queryparser/queryparser_internal.cc"
02328 break;
02329 case 32:
02330 #line 1651 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02331 { yygotominor.yy13 = yymsp[0].minor.yy0->as_wildcarded_query(state); }
02332 #line 2334 "queryparser/queryparser_internal.cc"
02333 break;
02334 case 33:
02335 #line 1654 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02336 { yygotominor.yy13 = yymsp[0].minor.yy0->as_partial_query(state); }
02337 #line 2339 "queryparser/queryparser_internal.cc"
02338 break;
02339 case 34:
02340 #line 1657 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02341 { yygotominor.yy13 = yymsp[-1].minor.yy1->as_phrase_query(); yy_destructor(19,&yymsp[-2].minor);
02342 yy_destructor(19,&yymsp[0].minor);
02343 }
02344 #line 2346 "queryparser/queryparser_internal.cc"
02345 break;
02346 case 35:
02347 #line 1660 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02348 { yygotominor.yy13 = yymsp[0].minor.yy1->as_phrase_query(); }
02349 #line 2351 "queryparser/queryparser_internal.cc"
02350 break;
02351 case 36:
02352 #line 1662 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02353 {
02354 yygotominor.yy13 = yymsp[0].minor.yy60->as_group(state);
02355 }
02356 #line 2358 "queryparser/queryparser_internal.cc"
02357 break;
02358 case 37:
02359 #line 1667 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02360 { yygotominor.yy13 = yymsp[0].minor.yy1->as_near_query(); }
02361 #line 2363 "queryparser/queryparser_internal.cc"
02362 break;
02363 case 38:
02364 #line 1670 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02365 { yygotominor.yy13 = yymsp[0].minor.yy1->as_adj_query(); }
02366 #line 2368 "queryparser/queryparser_internal.cc"
02367 break;
02368 case 39:
02369 #line 1673 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02370 { yygotominor.yy13 = yymsp[-1].minor.yy13; yy_destructor(20,&yymsp[-2].minor);
02371 yy_destructor(21,&yymsp[0].minor);
02372 }
02373 #line 2375 "queryparser/queryparser_internal.cc"
02374 break;
02375 case 40:
02376 #line 1675 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02377 {
02378 yygotominor.yy13 = new Query(yymsp[0].minor.yy0->get_query_with_synonyms());
02379 delete yymsp[0].minor.yy0;
02380 yy_destructor(10,&yymsp[-1].minor);
02381 }
02382 #line 2384 "queryparser/queryparser_internal.cc"
02383 break;
02384 case 41:
02385 #line 1686 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02386 {
02387 yygotominor.yy1 = new TermList;
02388 yygotominor.yy1->add_positional_term(yymsp[0].minor.yy0);
02389 }
02390 #line 2392 "queryparser/queryparser_internal.cc"
02391 break;
02392 case 42:
02393 case 44:
02394 #line 1691 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02395 {
02396 yygotominor.yy1 = yymsp[-1].minor.yy1;
02397 yygotominor.yy1->add_positional_term(yymsp[0].minor.yy0);
02398 }
02399 #line 2401 "queryparser/queryparser_internal.cc"
02400 break;
02401 case 43:
02402 #line 1703 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02403 {
02404 yygotominor.yy1 = new TermList;
02405 yygotominor.yy1->add_positional_term(yymsp[-1].minor.yy0);
02406 yygotominor.yy1->add_positional_term(yymsp[0].minor.yy0);
02407 }
02408 #line 2410 "queryparser/queryparser_internal.cc"
02409 break;
02410 case 45:
02411 #line 1720 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02412 {
02413 yygotominor.yy60 = new TermGroup;
02414 yygotominor.yy60->add_term(yymsp[-1].minor.yy0);
02415 yygotominor.yy60->add_term(yymsp[0].minor.yy0);
02416 }
02417 #line 2419 "queryparser/queryparser_internal.cc"
02418 break;
02419 case 46:
02420 #line 1726 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02421 {
02422 yygotominor.yy60 = yymsp[-1].minor.yy60;
02423 yygotominor.yy60->add_term(yymsp[0].minor.yy0);
02424 }
02425 #line 2427 "queryparser/queryparser_internal.cc"
02426 break;
02427 case 47:
02428 case 49:
02429 #line 1737 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02430 {
02431 yygotominor.yy1 = new TermList;
02432 yygotominor.yy1->add_positional_term(yymsp[-2].minor.yy0);
02433 yygotominor.yy1->add_positional_term(yymsp[0].minor.yy0);
02434 if (yymsp[-1].minor.yy0) {
02435 yygotominor.yy1->adjust_window(yymsp[-1].minor.yy0->get_termpos());
02436 delete yymsp[-1].minor.yy0;
02437 }
02438 }
02439 #line 2441 "queryparser/queryparser_internal.cc"
02440 break;
02441 case 48:
02442 case 50:
02443 #line 1747 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02444 {
02445 yygotominor.yy1 = yymsp[-2].minor.yy1;
02446 yygotominor.yy1->add_positional_term(yymsp[0].minor.yy0);
02447 if (yymsp[-1].minor.yy0) {
02448 yygotominor.yy1->adjust_window(yymsp[-1].minor.yy0->get_termpos());
02449 delete yymsp[-1].minor.yy0;
02450 }
02451 }
02452 #line 2454 "queryparser/queryparser_internal.cc"
02453 break;
02454 }
02455 yygoto = yyRuleInfo[yyruleno].lhs;
02456 yysize = yyRuleInfo[yyruleno].nrhs;
02457 yypParser->yystack.resize(yypParser->yystack.size() - yysize);
02458 yyact = yy_find_reduce_action(yypParser,yygoto);
02459 if( yyact < YYNSTATE ){
02460 yy_shift(yypParser,yyact,yygoto,&yygotominor);
02461 }else if( yyact == YYNSTATE + YYNRULE + 1 ){
02462 yy_accept(yypParser);
02463 }
02464 }
02465
02466
02467
02468
02469 static void yy_parse_failed(
02470 yyParser *yypParser
02471 ){
02472 ParseARG_FETCH;
02473 DEBUGLINE(QUERYPARSER, "Fail!");
02474 while( !yypParser->yystack.empty() ) yy_pop_parser_stack(yypParser);
02475
02476
02477 #line 1323 "/data/home/olly/tmp/xapian-svn-snapshot/tags/1.0.10/xapian/xapian-core/queryparser/queryparser.lemony"
02478
02479
02480 if (!state->error) state->error = "parse error";
02481 #line 2484 "queryparser/queryparser_internal.cc"
02482 ParseARG_STORE;
02483 }
02484
02485
02486
02487
02488 static void yy_syntax_error(
02489 yyParser *yypParser,
02490 int yymajor,
02491 YYMINORTYPE yyminor
02492 ){
02493 ParseARG_FETCH;
02494 (void)yymajor;
02495 (void)yyminor;
02496 #define TOKEN (yyminor.yy0)
02497 ParseARG_STORE;
02498 }
02499
02500
02501
02502
02503 static void yy_accept(
02504 yyParser *yypParser
02505 ){
02506 ParseARG_FETCH;
02507 DEBUGLINE(QUERYPARSER, "Accept!");
02508 while( !yypParser->yystack.empty() ) yy_pop_parser_stack(yypParser);
02509
02510
02511 ParseARG_STORE;
02512 }
02513
02514
02515
02516
02517
02518
02519
02520
02521
02522
02523
02524
02525
02526
02527
02528
02529
02530
02531
02532
02533 static void Parse(
02534 yyParser *yypParser,
02535 int yymajor,
02536 ParseTOKENTYPE yyminor
02537 ParseARG_PDECL
02538 ){
02539 YYMINORTYPE yyminorunion;
02540 int yyact;
02541 int yyendofinput;
02542 int yyerrorhit = 0;
02543
02544
02545 if( yypParser->yystack.empty() ){
02546 if( yymajor==0 ) return;
02547 yypParser->yystack.push_back(yyStackEntry());
02548 yypParser->yyerrcnt = -1;
02549 }
02550 yyminorunion.yy0 = yyminor;
02551 yyendofinput = (yymajor==0);
02552 ParseARG_STORE;
02553
02554 DEBUGLINE(QUERYPARSER, "Input " << ParseTokenName(yymajor) << " " <<
02555 (yyminor ? yyminor->name : "<<null>>"));
02556
02557 do{
02558 yyact = yy_find_shift_action(yypParser,yymajor);
02559 if( yyact<YYNSTATE ){
02560 yy_shift(yypParser,yyact,yymajor,&yyminorunion);
02561 yypParser->yyerrcnt--;
02562 if( yyendofinput && !yypParser->yystack.empty() ){
02563 yymajor = 0;
02564 }else{
02565 yymajor = YYNOCODE;
02566 }
02567 }else if( yyact < YYNSTATE + YYNRULE ){
02568 yy_reduce(yypParser,yyact-YYNSTATE);
02569 }else if( yyact == YY_ERROR_ACTION ){
02570 int yymx;
02571 DEBUGLINE(QUERYPARSER, "Syntax Error!");
02572 #ifdef YYERRORSYMBOL
02573
02574
02575
02576
02577
02578
02579
02580
02581
02582
02583
02584
02585
02586
02587
02588
02589
02590
02591
02592 if( yypParser->yyerrcnt<0 ){
02593 yy_syntax_error(yypParser,yymajor,yyminorunion);
02594 }
02595 yymx = yypParser->yystack.back().major;
02596 if( yymx==YYERRORSYMBOL || yyerrorhit ){
02597 DEBUGLINE(QUERYPARSER, "Discard input token " << ParseTokenName(yymajor));
02598 yy_destructor((YYCODETYPE)yymajor,&yyminorunion);
02599 yymajor = YYNOCODE;
02600 }else{
02601 while(
02602 !yypParser->yystack.empty() &&
02603 yymx != YYERRORSYMBOL &&
02604 (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
02605 ){
02606 yy_pop_parser_stack(yypParser);
02607 }
02608 if( yypParser->yystack.empty() || yymajor==0 ){
02609 yy_destructor((YYCODETYPE)yymajor,&yyminorunion);
02610 yy_parse_failed(yypParser);
02611 yymajor = YYNOCODE;
02612 }else if( yymx!=YYERRORSYMBOL ){
02613 YYMINORTYPE u2;
02614 u2.YYERRSYMDT = 0;
02615 yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
02616 }
02617 }
02618 yypParser->yyerrcnt = 3;
02619 yyerrorhit = 1;
02620 #else
02621
02622
02623
02624
02625
02626
02627
02628
02629
02630 if( yypParser->yyerrcnt<=0 ){
02631 yy_syntax_error(yypParser,yymajor,yyminorunion);
02632 }
02633 yypParser->yyerrcnt = 3;
02634 yy_destructor((YYCODETYPE)yymajor,&yyminorunion);
02635 if( yyendofinput ){
02636 yy_parse_failed(yypParser);
02637 }
02638 yymajor = YYNOCODE;
02639 #endif
02640 }else{
02641 yy_accept(yypParser);
02642 yymajor = YYNOCODE;
02643 }
02644 }while( yymajor!=YYNOCODE && !yypParser->yystack.empty() );
02645 return;
02646 }
02647
02648