00001
00002
00003
00004
00005
00006
00007
00008
00009 #line 1 "queryparser/queryparser.lemony"
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <config.h>
00034
00035 #include "omassert.h"
00036 #include "queryparser_internal.h"
00037 #include <xapian/error.h>
00038 #include <xapian/unicode.h>
00039 #include "str.h"
00040 #include "stringutils.h"
00041
00042
00043 #include "queryparser_token.h"
00044
00045 #include "cjk-tokenizer.h"
00046
00047 #include <algorithm>
00048 #include <limits>
00049 #include <list>
00050 #include <string>
00051
00052 #include <string.h>
00053
00054 using namespace std;
00055
00056 using namespace Xapian;
00057
00058 inline bool
00059 U_isupper(unsigned ch) {
00060 return (ch < 128 && C_isupper((unsigned char)ch));
00061 }
00062
00063 inline bool
00064 U_isdigit(unsigned ch) {
00065 return (ch < 128 && C_isdigit((unsigned char)ch));
00066 }
00067
00068 inline bool
00069 U_isalpha(unsigned ch) {
00070 return (ch < 128 && C_isalpha((unsigned char)ch));
00071 }
00072
00073 using Xapian::Unicode::is_whitespace;
00074
00075 inline bool
00076 is_not_whitespace(unsigned ch) {
00077 return !is_whitespace(ch);
00078 }
00079
00080 using Xapian::Unicode::is_wordchar;
00081
00082 inline bool
00083 is_not_wordchar(unsigned ch) {
00084 return !is_wordchar(ch);
00085 }
00086
00087 inline bool
00088 is_digit(unsigned ch) {
00089 return (Unicode::get_category(ch) == Unicode::DECIMAL_DIGIT_NUMBER);
00090 }
00091
00092
00093
00094 inline bool
00095 is_suffix(unsigned ch) {
00096 return ch == '+' || ch == '#';
00097 }
00098
00099 inline bool
00100 prefix_needs_colon(const string & prefix, unsigned ch)
00101 {
00102 if (!U_isupper(ch)) return false;
00103 string::size_type len = prefix.length();
00104 return (len > 1 && prefix[len - 1] != ':');
00105 }
00106
00107 using Unicode::is_currency;
00108
00109 inline bool
00110 is_positional(Xapian::Query::op op)
00111 {
00112 return (op == Xapian::Query::OP_PHRASE || op == Xapian::Query::OP_NEAR);
00113 }
00114
00116 struct filter_group_id {
00121 const PrefixInfo *prefix_info;
00122
00127 Xapian::valueno slot;
00128
00130 explicit filter_group_id(const PrefixInfo * prefix_info_)
00131 : prefix_info(prefix_info_), slot(Xapian::BAD_VALUENO) {}
00132
00134 explicit filter_group_id(Xapian::valueno slot_)
00135 : prefix_info(NULL), slot(slot_) {}
00136
00138 bool operator<(const filter_group_id & other) const {
00139
00140 if (slot != other.slot)
00141 return slot < other.slot;
00142 if (!prefix_info || prefix_info == other.prefix_info)
00143 return false;
00144 if (!other.prefix_info)
00145 return true;
00146 return prefix_info->prefixes < other.prefix_info->prefixes;
00147 }
00148 };
00149
00150 class Terms;
00151
00158 class Term {
00159 State * state;
00160
00161 public:
00162 string name;
00163 const PrefixInfo * prefix_info;
00164 string unstemmed;
00165 QueryParser::stem_strategy stem;
00166 termpos pos;
00167
00168 Term(const string &name_, termpos pos_) : name(name_), stem(QueryParser::STEM_NONE), pos(pos_) { }
00169 Term(const string &name_) : name(name_), stem(QueryParser::STEM_NONE), pos(0) { }
00170 Term(const string &name_, const PrefixInfo * prefix_info_)
00171 : name(name_), prefix_info(prefix_info_),
00172 stem(QueryParser::STEM_NONE), pos(0) { }
00173 Term(termpos pos_) : stem(QueryParser::STEM_NONE), pos(pos_) { }
00174 Term(State * state_, const string &name_, const PrefixInfo * prefix_info_,
00175 const string &unstemmed_,
00176 QueryParser::stem_strategy stem_ = QueryParser::STEM_NONE,
00177 termpos pos_ = 0)
00178 : state(state_), name(name_), prefix_info(prefix_info_),
00179 unstemmed(unstemmed_), stem(stem_), pos(pos_) { }
00180
00181 Term(valueno slot, const string &a, const string &b)
00182 : name(a), unstemmed(b), pos(slot) { }
00183
00184 string make_term(const string & prefix) const;
00185
00186 void need_positions() {
00187 if (stem == QueryParser::STEM_SOME) stem = QueryParser::STEM_NONE;
00188 }
00189
00190 termpos get_termpos() const { return pos; }
00191
00192 filter_group_id get_filter_group_id() const {
00193 return filter_group_id(prefix_info);
00194 }
00195
00196 Query * as_wildcarded_query(State * state) const;
00197
00206 Query * as_partial_query(State * state_) const;
00207
00209 Query * as_cjk_query() const;
00210
00212 void as_positional_cjk_term(Terms * terms) const;
00213
00215 Query as_value_range_query() const;
00216
00217 Query get_query() const;
00218
00219 Query get_query_with_synonyms() const;
00220
00221 Query get_query_with_auto_synonyms() const;
00222 };
00223
00225 class State {
00226 QueryParser::Internal * qpi;
00227
00228 public:
00229 Query query;
00230 const char * error;
00231 unsigned flags;
00232
00233 State(QueryParser::Internal * qpi_, unsigned flags_)
00234 : qpi(qpi_), error(NULL), flags(flags_) { }
00235
00236 string stem_term(const string &term) {
00237 return qpi->stemmer(term);
00238 }
00239
00240 void add_to_stoplist(const Term * term) {
00241 qpi->stoplist.push_back(term->name);
00242 }
00243
00244 void add_to_unstem(const string & term, const string & unstemmed) {
00245 qpi->unstem.insert(make_pair(term, unstemmed));
00246 }
00247
00248 Term * value_range(const string &a, const string &b) {
00249 list<ValueRangeProcessor *>::const_iterator i;
00250 for (i = qpi->valrangeprocs.begin(); i != qpi->valrangeprocs.end(); ++i) {
00251 string start = a;
00252 string end = b;
00253 Xapian::valueno slot = (**i)(start, end);
00254 if (slot != Xapian::BAD_VALUENO) {
00255 return new Term(slot, start, end);
00256 }
00257 }
00258 return NULL;
00259 }
00260
00261 Query::op default_op() const { return qpi->default_op; }
00262
00263 bool is_stopword(const Term *term) const {
00264 return qpi->stopper && (*qpi->stopper)(term->name);
00265 }
00266
00267 Database get_database() const {
00268 return qpi->db;
00269 }
00270
00271 const Stopper * get_stopper() const {
00272 return qpi->stopper;
00273 }
00274
00275 size_t stoplist_size() const {
00276 return qpi->stoplist.size();
00277 }
00278
00279 void stoplist_resize(size_t s) {
00280 qpi->stoplist.resize(s);
00281 }
00282
00283 Xapian::termcount get_max_wildcard_expansion() const {
00284 return qpi->max_wildcard_expansion;
00285 }
00286 };
00287
00288 string
00289 Term::make_term(const string & prefix) const
00290 {
00291 string term;
00292 if (stem == QueryParser::STEM_SOME || stem == QueryParser::STEM_ALL_Z)
00293 term += 'Z';
00294 if (!prefix.empty()) {
00295 term += prefix;
00296 if (prefix_needs_colon(prefix, name[0])) term += ':';
00297 }
00298 if (stem != QueryParser::STEM_NONE) {
00299 term += state->stem_term(name);
00300 } else {
00301 term += name;
00302 }
00303
00304 if (!unstemmed.empty())
00305 state->add_to_unstem(term, unstemmed);
00306 return term;
00307 }
00308
00309 Query
00310 Term::get_query_with_synonyms() const
00311 {
00312 Query q = get_query();
00313
00314
00315 const list<string> & prefixes = prefix_info->prefixes;
00316 list<string>::const_iterator piter;
00317 for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
00318
00319 string term;
00320 if (!piter->empty()) {
00321 term += *piter;
00322 if (prefix_needs_colon(*piter, name[0])) term += ':';
00323 }
00324 term += name;
00325
00326 Xapian::Database db = state->get_database();
00327 Xapian::TermIterator syn = db.synonyms_begin(term);
00328 Xapian::TermIterator end = db.synonyms_end(term);
00329 if (syn == end && stem != QueryParser::STEM_NONE) {
00330
00331 term = 'Z';
00332 if (!piter->empty()) {
00333 term += *piter;
00334 if (prefix_needs_colon(*piter, name[0])) term += ':';
00335 }
00336 term += state->stem_term(name);
00337 syn = db.synonyms_begin(term);
00338 end = db.synonyms_end(term);
00339 }
00340 while (syn != end) {
00341 q = Query(Query::OP_SYNONYM, q, Query(*syn, 1, pos));
00342 ++syn;
00343 }
00344 }
00345 return q;
00346 }
00347
00348 Query
00349 Term::get_query_with_auto_synonyms() const
00350 {
00351 if (state->flags & QueryParser::FLAG_AUTO_SYNONYMS)
00352 return get_query_with_synonyms();
00353
00354 return get_query();
00355 }
00356
00357 static void
00358 add_to_query(Query *& q, Query::op op, Query * term)
00359 {
00360 Assert(term);
00361 if (q) {
00362 *q = Query(op, *q, *term);
00363 delete term;
00364 } else {
00365 q = term;
00366 }
00367 }
00368
00369 static void
00370 add_to_query(Query *& q, Query::op op, const Query & term)
00371 {
00372 if (q) {
00373 *q = Query(op, *q, term);
00374 } else {
00375 q = new Query(term);
00376 }
00377 }
00378
00379 Query
00380 Term::get_query() const
00381 {
00382 const list<string> & prefixes = prefix_info->prefixes;
00383 Assert(prefixes.size() >= 1);
00384 list<string>::const_iterator piter = prefixes.begin();
00385 Query q(make_term(*piter), 1, pos);
00386 while (++piter != prefixes.end()) {
00387 q = Query(Query::OP_OR, q, Query(make_term(*piter), 1, pos));
00388 }
00389 return q;
00390 }
00391
00392 Query *
00393 Term::as_wildcarded_query(State * state_) const
00394 {
00395 const Database & db = state_->get_database();
00396 vector<Query> subqs;
00397
00398 const list<string> & prefixes = prefix_info->prefixes;
00399 list<string>::const_iterator piter;
00400 Xapian::termcount expansion_count = 0;
00401 Xapian::termcount max = state_->get_max_wildcard_expansion();
00402 for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
00403 string root = *piter;
00404 root += name;
00405 TermIterator t = db.allterms_begin(root);
00406 while (t != db.allterms_end(root)) {
00407 if (max != 0 && ++expansion_count > max) {
00408 string msg("Wildcard ");
00409 msg += unstemmed;
00410 msg += "* expands to more than ";
00411 msg += str(max);
00412 msg += " terms";
00413 throw Xapian::QueryParserError(msg);
00414 }
00415 subqs.push_back(Query(*t, 1, pos));
00416 ++t;
00417 }
00418 }
00419 Query * q = new Query(Query::OP_SYNONYM, subqs.begin(), subqs.end());
00420 delete this;
00421 return q;
00422 }
00423
00424 Query *
00425 Term::as_partial_query(State * state_) const
00426 {
00427 const Database & db = state_->get_database();
00428 vector<Query> subqs_partial;
00429 vector<Query> subqs_full;
00430
00431 const list<string> & prefixes = prefix_info->prefixes;
00432 list<string>::const_iterator piter;
00433 for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
00434 string root = *piter;
00435 root += name;
00436 TermIterator t = db.allterms_begin(root);
00437 while (t != db.allterms_end(root)) {
00438 subqs_partial.push_back(Query(*t, 1, pos));
00439 ++t;
00440 }
00441
00442 subqs_full.push_back(Query(make_term(*piter), 1, pos));
00443 }
00444 Query * q = new Query(Query::OP_OR,
00445 Query(Query::OP_SYNONYM,
00446 subqs_partial.begin(), subqs_partial.end()),
00447 Query(Query::OP_SYNONYM,
00448 subqs_full.begin(), subqs_full.end()));
00449 delete this;
00450 return q;
00451 }
00452
00453 Query *
00454 Term::as_cjk_query() const
00455 {
00456 vector<Query> prefix_cjk;
00457 const list<string> & prefixes = prefix_info->prefixes;
00458 list<string>::const_iterator piter;
00459 for (CJKTokenIterator tk(name); tk != CJKTokenIterator(); ++tk) {
00460 for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
00461 string cjk = *piter;
00462 cjk += *tk;
00463 prefix_cjk.push_back(Query(cjk, 1, pos));
00464 }
00465 }
00466 Query * q = new Query(Query::OP_AND, prefix_cjk.begin(), prefix_cjk.end());
00467 delete this;
00468 return q;
00469 }
00470
00471 Query
00472 Term::as_value_range_query() const
00473 {
00474 Query q;
00475 if (unstemmed.empty())
00476 q = Query(Query::OP_VALUE_GE, pos, name);
00477 else
00478 q = Query(Query::OP_VALUE_RANGE, pos, name, unstemmed);
00479 delete this;
00480 return q;
00481 }
00482
00483 inline bool
00484 is_phrase_generator(unsigned ch)
00485 {
00486
00487
00488
00489 return (ch && ch < 128 && strchr(".-/:\\@", ch) != NULL);
00490 }
00491
00492 inline bool
00493 is_stem_preventer(unsigned ch)
00494 {
00495 return (ch && ch < 128 && strchr("(/\\@<>=*[{\"", ch) != NULL);
00496 }
00497
00498 inline bool
00499 should_stem(const string & term)
00500 {
00501 const unsigned int SHOULD_STEM_MASK =
00502 (1 << Unicode::LOWERCASE_LETTER) |
00503 (1 << Unicode::TITLECASE_LETTER) |
00504 (1 << Unicode::MODIFIER_LETTER) |
00505 (1 << Unicode::OTHER_LETTER);
00506 Utf8Iterator u(term);
00507 return ((SHOULD_STEM_MASK >> Unicode::get_category(*u)) & 1);
00508 }
00509
00513 const unsigned UNICODE_IGNORE = numeric_limits<unsigned>::max();
00514
00515 inline unsigned check_infix(unsigned ch) {
00516 if (ch == '\'' || ch == '&' || ch == 0xb7 || ch == 0x5f4 || ch == 0x2027) {
00517
00518
00519
00520
00521 return ch;
00522 }
00523
00524
00525 if (ch == 0x2019 || ch == 0x201b) return '\'';
00526 if (ch >= 0x200b && (ch <= 0x200d || ch == 0x2060 || ch == 0xfeff))
00527 return UNICODE_IGNORE;
00528 return 0;
00529 }
00530
00531 inline unsigned check_infix_digit(unsigned ch) {
00532
00533 switch (ch) {
00534 case ',':
00535 case '.':
00536 case ';':
00537 case 0x037e:
00538 case 0x0589:
00539 case 0x060D:
00540 case 0x07F8:
00541 case 0x2044:
00542 case 0xFE10:
00543 case 0xFE13:
00544 case 0xFE14:
00545 return ch;
00546 }
00547 if (ch >= 0x200b && (ch <= 0x200d || ch == 0x2060 || ch == 0xfeff))
00548 return UNICODE_IGNORE;
00549 return 0;
00550 }
00551
00552 struct yyParser;
00553
00554
00555 static yyParser *ParseAlloc();
00556 static void ParseFree(yyParser *);
00557 static void Parse(yyParser *, int, Term *, State *);
00558 static void yy_parse_failed(yyParser *);
00559
00560 void
00561 QueryParser::Internal::add_prefix(const string &field, const string &prefix,
00562 filter_type type)
00563 {
00564 map<string, PrefixInfo>::iterator p = prefixmap.find(field);
00565 if (p == prefixmap.end()) {
00566 prefixmap.insert(make_pair(field, PrefixInfo(type, prefix)));
00567 } else {
00568
00569 if (p->second.type != type) {
00570 throw Xapian::InvalidOperationError("Can't use add_prefix() and add_boolean_prefix() on the same field name, or add_boolean_prefix() with different values of the 'exclusive' parameter");
00571 }
00572 p->second.prefixes.push_back(prefix);
00573 }
00574 }
00575
00576 string
00577 QueryParser::Internal::parse_term(Utf8Iterator &it, const Utf8Iterator &end,
00578 bool cjk_ngram, bool & is_cjk_term,
00579 bool &was_acronym)
00580 {
00581 string term;
00582
00583
00584 if (U_isupper(*it)) {
00585 string t;
00586 Utf8Iterator p = it;
00587 do {
00588 Unicode::append_utf8(t, *p++);
00589 } while (p != end && *p == '.' && ++p != end && U_isupper(*p));
00590
00591
00592 if (t.length() > 1) {
00593
00594
00595
00596 if (p == end || !is_wordchar(*p)) {
00597 it = p;
00598 swap(term, t);
00599 }
00600 }
00601 }
00602 was_acronym = !term.empty();
00603
00604 if (cjk_ngram && term.empty() && CJK::codepoint_is_cjk(*it)) {
00605 term = CJK::get_cjk(it);
00606 is_cjk_term = true;
00607 }
00608
00609 if (term.empty()) {
00610 unsigned prevch = *it;
00611 Unicode::append_utf8(term, prevch);
00612 while (++it != end) {
00613 if (cjk_ngram && CJK::codepoint_is_cjk(*it)) break;
00614 unsigned ch = *it;
00615 if (!is_wordchar(ch)) {
00616
00617
00618
00619 Utf8Iterator p = it;
00620 ++p;
00621 if (p == end || !is_wordchar(*p)) break;
00622 unsigned nextch = *p;
00623 if (is_digit(prevch) && is_digit(nextch)) {
00624 ch = check_infix_digit(ch);
00625 } else {
00626 ch = check_infix(ch);
00627 }
00628 if (!ch) break;
00629 if (ch == UNICODE_IGNORE)
00630 continue;
00631 }
00632 Unicode::append_utf8(term, ch);
00633 prevch = ch;
00634 }
00635 if (it != end && is_suffix(*it)) {
00636 string suff_term = term;
00637 Utf8Iterator p = it;
00638
00639 do {
00640 if (suff_term.size() - term.size() == 3) {
00641 suff_term.resize(0);
00642 break;
00643 }
00644 suff_term += *p;
00645 } while (is_suffix(*++p));
00646 if (!suff_term.empty() && (p == end || !is_wordchar(*p))) {
00647
00648
00649
00650
00651 bool use_suff_term = false;
00652 string lc = Unicode::tolower(suff_term);
00653 if (db.term_exists(lc)) {
00654 use_suff_term = true;
00655 } else {
00656 lc = Unicode::tolower(term);
00657 if (!db.term_exists(lc)) use_suff_term = true;
00658 }
00659 if (use_suff_term) {
00660 term = suff_term;
00661 it = p;
00662 }
00663 }
00664 }
00665 }
00666 return term;
00667 }
00668
00669 class ParserHandler {
00670 yyParser * parser;
00671
00672 public:
00673 explicit ParserHandler(yyParser * parser_) : parser(parser_) { }
00674 operator yyParser*() { return parser; }
00675 ~ParserHandler() { ParseFree(parser); }
00676 };
00677
00678 Query
00679 QueryParser::Internal::parse_query(const string &qs, unsigned flags,
00680 const string &default_prefix)
00681 {
00682 bool cjk_ngram = CJK::is_cjk_enabled();
00683
00684
00685 bool value_ranges;
00686 value_ranges = !valrangeprocs.empty() && (qs.find("..") != string::npos);
00687
00688 termpos term_pos = 1;
00689 Utf8Iterator it(qs), end;
00690
00691 State state(this, flags);
00692
00693
00694
00695 int correction_offset = 0;
00696 corrected_query.resize(0);
00697
00698
00699 list<const PrefixInfo *> prefix_stack;
00700
00701
00702
00703 const PrefixInfo def_pfx(NON_BOOLEAN, default_prefix);
00704 {
00705 const PrefixInfo * default_prefix_info = &def_pfx;
00706 if (default_prefix.empty()) {
00707 map<string, PrefixInfo>::const_iterator f = prefixmap.find("");
00708 if (f != prefixmap.end()) default_prefix_info = &(f->second);
00709 }
00710
00711
00712 prefix_stack.push_back(default_prefix_info);
00713 }
00714
00715 ParserHandler pParser(ParseAlloc());
00716
00717 unsigned newprev = ' ';
00718 main_lex_loop:
00719 enum {
00720 DEFAULT, IN_QUOTES, IN_PREFIXED_QUOTES, IN_PHRASED_TERM, IN_GROUP,
00721 IN_GROUP2, EXPLICIT_SYNONYM
00722 } mode = DEFAULT;
00723 while (it != end && !state.error) {
00724 bool last_was_operator = false;
00725 bool last_was_operator_needing_term = false;
00726 if (mode == EXPLICIT_SYNONYM) mode = DEFAULT;
00727 if (false) {
00728 just_had_operator:
00729 if (it == end) break;
00730 mode = DEFAULT;
00731 last_was_operator_needing_term = false;
00732 last_was_operator = true;
00733 }
00734 if (false) {
00735 just_had_operator_needing_term:
00736 last_was_operator_needing_term = true;
00737 last_was_operator = true;
00738 }
00739 if (mode == IN_PHRASED_TERM) mode = DEFAULT;
00740 if (is_whitespace(*it)) {
00741 newprev = ' ';
00742 ++it;
00743 it = find_if(it, end, is_not_whitespace);
00744 if (it == end) break;
00745 }
00746
00747 if (value_ranges &&
00748 (mode == DEFAULT || mode == IN_GROUP || mode == IN_GROUP2)) {
00749
00750
00751
00752
00753 Utf8Iterator it_initial = it;
00754 Utf8Iterator p = it;
00755 unsigned ch = 0;
00756 while (p != end) {
00757 if (ch == '.' && *p == '.') {
00758 string a;
00759 while (it != p) {
00760 Unicode::append_utf8(a, *it++);
00761 }
00762
00763 a.resize(a.size() - 1);
00764 ++p;
00765
00766
00767 if (!a.empty() || (p != end && *p > ' ' && *p != ')')) {
00768 string b;
00769
00770
00771
00772 while (p != end && *p > ' ' && *p != ')') {
00773 Unicode::append_utf8(b, *p++);
00774 }
00775 Term * range = state.value_range(a, b);
00776 if (!range) {
00777 state.error = "Unknown range operation";
00778 if (a.find(':', 1) == string::npos) {
00779 goto done;
00780 }
00781
00782
00783 it = it_initial;
00784 break;
00785 }
00786 Parse(pParser, RANGE, range, &state);
00787 }
00788 it = p;
00789 goto main_lex_loop;
00790 }
00791 ch = *p;
00792 if (!(is_wordchar(ch) || is_currency(ch) ||
00793 (ch < 128 && strchr("%,-./:@", ch)))) break;
00794 ++p;
00795 }
00796 }
00797
00798 if (!is_wordchar(*it)) {
00799 unsigned prev = newprev;
00800 unsigned ch = *it++;
00801 newprev = ch;
00802
00803 if (mode == IN_GROUP || mode == IN_GROUP2)
00804 mode = DEFAULT;
00805 switch (ch) {
00806 case '"':
00807 if (mode == DEFAULT) {
00808
00809 it = find_if(it, end, is_not_whitespace);
00810 if (it == end) {
00811
00812
00813
00814 goto done;
00815 }
00816 if (*it == '"') {
00817
00818
00819
00820 newprev = *it++;
00821 break;
00822 }
00823 }
00824 if (flags & QueryParser::FLAG_PHRASE) {
00825 Parse(pParser, QUOTE, NULL, &state);
00826 if (mode == DEFAULT) {
00827 mode = IN_QUOTES;
00828 } else {
00829
00830 if (mode == IN_PREFIXED_QUOTES)
00831 prefix_stack.pop_back();
00832 mode = DEFAULT;
00833 }
00834 }
00835 break;
00836
00837 case '+': case '-':
00838
00839 if (it == end) goto done;
00840 if (prev > ' ' && prev != '(') {
00841
00842 break;
00843 }
00844 if (is_whitespace(*it) || *it == '+' || *it == '-') {
00845
00846
00847
00848 newprev = *it++;
00849 break;
00850 }
00851 if (mode == DEFAULT && (flags & FLAG_LOVEHATE)) {
00852 int token;
00853 if (ch == '+') {
00854 token = LOVE;
00855 } else if (last_was_operator) {
00856 token = HATE_AFTER_AND;
00857 } else {
00858 token = HATE;
00859 }
00860 Parse(pParser, token, NULL, &state);
00861 goto just_had_operator_needing_term;
00862 }
00863
00864
00865 break;
00866
00867 case '(':
00868
00869 it = find_if(it, end, is_not_whitespace);
00870
00871 if (it == end) goto done;
00872 if (prev > ' ' && strchr("()+-", prev) == NULL) {
00873
00874 break;
00875 }
00876 if (*it == ')') {
00877
00878 newprev = *it++;
00879 break;
00880 }
00881 if (mode == DEFAULT && (flags & FLAG_BOOLEAN)) {
00882 prefix_stack.push_back(prefix_stack.back());
00883 Parse(pParser, BRA, NULL, &state);
00884 }
00885 break;
00886
00887 case ')':
00888 if (mode == DEFAULT && (flags & FLAG_BOOLEAN)) {
00889
00890
00891
00892 if (prefix_stack.size() > 1) prefix_stack.pop_back();
00893 Parse(pParser, KET, NULL, &state);
00894 }
00895 break;
00896
00897 case '~':
00898
00899 if (it == end) goto done;
00900 if (mode == DEFAULT && (flags & FLAG_SYNONYM)) {
00901 if (prev > ' ' && strchr("+-(", prev) == NULL) {
00902
00903 break;
00904 }
00905 if (!is_wordchar(*it)) {
00906
00907 break;
00908 }
00909 Parse(pParser, SYNONYM, NULL, &state);
00910 mode = EXPLICIT_SYNONYM;
00911 goto just_had_operator_needing_term;
00912 }
00913 break;
00914 }
00915
00916 continue;
00917 }
00918
00919 Assert(is_wordchar(*it));
00920
00921 size_t term_start_index = it.raw() - qs.data();
00922
00923 newprev = 'A';
00924
00925
00926 const PrefixInfo * prefix_info = NULL;
00927 if ((mode == DEFAULT || mode == IN_GROUP || mode == IN_GROUP2 || mode == EXPLICIT_SYNONYM) &&
00928 !prefixmap.empty()) {
00929
00930 Utf8Iterator p = find_if(it, end, is_not_wordchar);
00931 if (p != end && *p == ':' && ++p != end && *p > ' ' && *p != ')') {
00932 string field;
00933 p = it;
00934 while (*p != ':')
00935 Unicode::append_utf8(field, *p++);
00936 map<string, PrefixInfo>::const_iterator f;
00937 f = prefixmap.find(field);
00938 if (f != prefixmap.end()) {
00939
00940
00941 unsigned ch = *++p;
00942 prefix_info = &(f->second);
00943
00944 if (prefix_info->type != NON_BOOLEAN) {
00945
00946 if (mode == IN_GROUP || mode == IN_GROUP2)
00947 mode = DEFAULT;
00948 it = p;
00949 string name;
00950 if (it != end && *it == '"') {
00951
00952 ++it;
00953 while (it != end) {
00954 if (*it == '"') {
00955
00956 if (++it == end || *it != '"')
00957 break;
00958 }
00959 Unicode::append_utf8(name, *it++);
00960 }
00961 } else {
00962
00963
00964
00965
00966 while (it != end && *it > ' ' && *it != ')')
00967 Unicode::append_utf8(name, *it++);
00968 }
00969
00970 field += ':';
00971 field += name;
00972
00973 state.error = NULL;
00974 Term * token = new Term(&state, name, prefix_info, field);
00975 Parse(pParser, BOOLEAN_FILTER, token, &state);
00976 continue;
00977 }
00978
00979 if (ch == '"' && (flags & FLAG_PHRASE)) {
00980
00981 mode = IN_PREFIXED_QUOTES;
00982 Parse(pParser, QUOTE, NULL, &state);
00983 it = p;
00984 newprev = ch;
00985 ++it;
00986 prefix_stack.push_back(prefix_info);
00987 continue;
00988 }
00989
00990 if (ch == '(' && (flags & FLAG_BOOLEAN)) {
00991
00992 mode = DEFAULT;
00993 Parse(pParser, BRA, NULL, &state);
00994 it = p;
00995 newprev = ch;
00996 ++it;
00997 prefix_stack.push_back(prefix_info);
00998 continue;
00999 }
01000
01001 if (ch != ':') {
01002
01003 while (is_phrase_generator(ch)) {
01004 if (++p == end)
01005 goto not_prefix;
01006 ch = *p;
01007 }
01008 }
01009
01010 if (is_wordchar(ch)) {
01011
01012 it = p;
01013 } else {
01014 not_prefix:
01015
01016
01017 prefix_info = NULL;
01018 }
01019 }
01020 }
01021 }
01022
01023 phrased_term:
01024 bool was_acronym;
01025 bool is_cjk_term = false;
01026 string term = parse_term(it, end, cjk_ngram, is_cjk_term, was_acronym);
01027
01028
01029 if ((mode == DEFAULT || mode == IN_GROUP || mode == IN_GROUP2) &&
01030 (flags & FLAG_BOOLEAN) &&
01031
01032 !was_acronym &&
01033 !prefix_info &&
01034 term.size() >= 2 && term.size() <= 4 && U_isalpha(term[0])) {
01035
01036 string op = term;
01037 if (flags & FLAG_BOOLEAN_ANY_CASE) {
01038 for (string::iterator i = op.begin(); i != op.end(); ++i) {
01039 *i = C_toupper(*i);
01040 }
01041 }
01042 if (op.size() == 3) {
01043 if (op == "AND") {
01044 Parse(pParser, AND, NULL, &state);
01045 goto just_had_operator;
01046 }
01047 if (op == "NOT") {
01048 Parse(pParser, NOT, NULL, &state);
01049 goto just_had_operator;
01050 }
01051 if (op == "XOR") {
01052 Parse(pParser, XOR, NULL, &state);
01053 goto just_had_operator;
01054 }
01055 if (op == "ADJ") {
01056 if (it != end && *it == '/') {
01057 size_t width = 0;
01058 Utf8Iterator p = it;
01059 while (++p != end && U_isdigit(*p)) {
01060 width = (width * 10) + (*p - '0');
01061 }
01062 if (width && (p == end || is_whitespace(*p))) {
01063 it = p;
01064 Parse(pParser, ADJ, new Term(width), &state);
01065 goto just_had_operator;
01066 }
01067 } else {
01068 Parse(pParser, ADJ, NULL, &state);
01069 goto just_had_operator;
01070 }
01071 }
01072 } else if (op.size() == 2) {
01073 if (op == "OR") {
01074 Parse(pParser, OR, NULL, &state);
01075 goto just_had_operator;
01076 }
01077 } else if (op.size() == 4) {
01078 if (op == "NEAR") {
01079 if (it != end && *it == '/') {
01080 size_t width = 0;
01081 Utf8Iterator p = it;
01082 while (++p != end && U_isdigit(*p)) {
01083 width = (width * 10) + (*p - '0');
01084 }
01085 if (width && (p == end || is_whitespace(*p))) {
01086 it = p;
01087 Parse(pParser, NEAR, new Term(width), &state);
01088 goto just_had_operator;
01089 }
01090 } else {
01091 Parse(pParser, NEAR, NULL, &state);
01092 goto just_had_operator;
01093 }
01094 }
01095 }
01096 }
01097
01098
01099 if (!prefix_info) prefix_info = prefix_stack.back();
01100
01101 Assert(prefix_info->type == NON_BOOLEAN);
01102
01103 {
01104 string unstemmed_term(term);
01105 term = Unicode::tolower(term);
01106
01107
01108
01109 stem_strategy stem_term = stem_action;
01110 if (stem_term != STEM_NONE) {
01111 if (!stemmer.internal.get()) {
01112
01113 stem_term = STEM_NONE;
01114 } else if (stem_term == STEM_SOME) {
01115 if (!should_stem(unstemmed_term) ||
01116 (it != end && is_stem_preventer(*it))) {
01117
01118 stem_term = STEM_NONE;
01119 }
01120 }
01121 }
01122
01123 Term * term_obj = new Term(&state, term, prefix_info,
01124 unstemmed_term, stem_term, term_pos++);
01125
01126 if (is_cjk_term) {
01127 Parse(pParser, CJKTERM, term_obj, &state);
01128 if (it == end) break;
01129 continue;
01130 }
01131
01132 if (mode == DEFAULT || mode == IN_GROUP || mode == IN_GROUP2) {
01133 if (it != end) {
01134 if ((flags & FLAG_WILDCARD) && *it == '*') {
01135 Utf8Iterator p(it);
01136 ++p;
01137 if (p == end || !is_wordchar(*p)) {
01138 it = p;
01139 if (mode == IN_GROUP || mode == IN_GROUP2) {
01140
01141
01142 if (mode == IN_GROUP2)
01143 Parse(pParser, EMPTY_GROUP_OK, NULL, &state);
01144 mode = DEFAULT;
01145 }
01146
01147
01148 Parse(pParser, WILD_TERM, term_obj, &state);
01149 continue;
01150 }
01151 }
01152 } else {
01153 if (flags & FLAG_PARTIAL) {
01154 if (mode == IN_GROUP || mode == IN_GROUP2) {
01155
01156
01157 if (mode == IN_GROUP2)
01158 Parse(pParser, EMPTY_GROUP_OK, NULL, &state);
01159 mode = DEFAULT;
01160 }
01161
01162
01163 Parse(pParser, PARTIAL_TERM, term_obj, &state);
01164 continue;
01165 }
01166 }
01167 }
01168
01169
01170
01171 if ((flags & FLAG_SPELLING_CORRECTION) && !was_acronym) {
01172 const list<string> & pfxes = prefix_info->prefixes;
01173 list<string>::const_iterator pfx_it;
01174 for (pfx_it = pfxes.begin(); pfx_it != pfxes.end(); ++pfx_it) {
01175 if (!pfx_it->empty())
01176 continue;
01177 const string & suggest = db.get_spelling_suggestion(term);
01178 if (!suggest.empty()) {
01179 if (corrected_query.empty()) corrected_query = qs;
01180 size_t term_end_index = it.raw() - qs.data();
01181 size_t n = term_end_index - term_start_index;
01182 size_t pos = term_start_index + correction_offset;
01183 corrected_query.replace(pos, n, suggest);
01184 correction_offset += suggest.size();
01185 correction_offset -= n;
01186 }
01187 break;
01188 }
01189 }
01190
01191 if (mode == IN_PHRASED_TERM) {
01192 Parse(pParser, PHR_TERM, term_obj, &state);
01193 } else {
01194
01195
01196 if ((mode == IN_GROUP || mode == IN_GROUP2) &&
01197 is_phrase_generator(*it)) {
01198
01199 Utf8Iterator p = it;
01200 do {
01201 ++p;
01202 } while (p != end && is_phrase_generator(*p));
01203
01204
01205 if (p != end && is_wordchar(*p)) {
01206 mode = DEFAULT;
01207 }
01208 }
01209
01210 int token = TERM;
01211 if (mode == IN_GROUP || mode == IN_GROUP2) {
01212 mode = IN_GROUP2;
01213 token = GROUP_TERM;
01214 }
01215 Parse(pParser, token, term_obj, &state);
01216 if (token == TERM && mode != DEFAULT)
01217 continue;
01218 }
01219 }
01220
01221 if (it == end) break;
01222
01223 if (is_phrase_generator(*it)) {
01224
01225 do {
01226 ++it;
01227 } while (it != end && is_phrase_generator(*it));
01228
01229
01230 if (it != end && is_wordchar(*it)) {
01231 mode = IN_PHRASED_TERM;
01232 term_start_index = it.raw() - qs.data();
01233 goto phrased_term;
01234 }
01235 } else if (mode == DEFAULT || mode == IN_GROUP || mode == IN_GROUP2) {
01236 int old_mode = mode;
01237 mode = DEFAULT;
01238 if (!last_was_operator_needing_term && is_whitespace(*it)) {
01239 newprev = ' ';
01240
01241 do {
01242 ++it;
01243 } while (it != end && is_whitespace(*it));
01244
01245
01246 if (it != end && is_wordchar(*it)) {
01247 if (old_mode == IN_GROUP || old_mode == IN_GROUP2) {
01248 mode = IN_GROUP2;
01249 } else {
01250 mode = IN_GROUP;
01251 }
01252 }
01253 }
01254 }
01255 }
01256 done:
01257 if (!state.error) {
01258
01259 if (mode == IN_QUOTES || mode == IN_PREFIXED_QUOTES)
01260 Parse(pParser, QUOTE, NULL, &state);
01261
01262
01263 while (prefix_stack.size() > 1) {
01264 Parse(pParser, KET, NULL, &state);
01265 prefix_stack.pop_back();
01266 }
01267 Parse(pParser, 0, NULL, &state);
01268 }
01269
01270 errmsg = state.error;
01271 return state.query;
01272 }
01273
01274 struct ProbQuery {
01275 Query * query;
01276 Query * love;
01277 Query * hate;
01278
01279
01280
01281 map<filter_group_id, Query> filter;
01282
01283 ProbQuery() : query(0), love(0), hate(0) { }
01284 ~ProbQuery() {
01285 delete query;
01286 delete love;
01287 delete hate;
01288 }
01289
01290 void add_filter(const filter_group_id & id, const Query & q) {
01291 filter[id] = q;
01292 }
01293
01294 void append_filter(const filter_group_id & id, const Query & qnew) {
01295 Query & q = filter[id];
01296
01297
01298 bool exclusive = (id.prefix_info->type == BOOLEAN_EXCLUSIVE);
01299 Query::op op = exclusive ? Query::OP_OR : Query::OP_AND;
01300 q = Query(op, q, qnew);
01301 }
01302
01303 void add_filter_range(Xapian::valueno slot, const Query & range) {
01304 filter[filter_group_id(slot)] = range;
01305 }
01306
01307 void append_filter_range(Xapian::valueno slot, const Query & range) {
01308 Query & q = filter[filter_group_id(slot)];
01309 q = Query(Query::OP_OR, q, range);
01310 }
01311
01312 Query merge_filters() const {
01313 map<filter_group_id, Query>::const_iterator i = filter.begin();
01314 Assert(i != filter.end());
01315 Query q = i->second;
01316 while (++i != filter.end()) {
01317 q = Query(Query::OP_AND, q, i->second);
01318 }
01319 return q;
01320 }
01321 };
01322
01324 class TermGroup {
01325 vector<Term *> terms;
01326
01332 bool empty_ok;
01333
01334 public:
01335 TermGroup() : empty_ok(false) { }
01336
01338 void add_term(Term * term) {
01339 terms.push_back(term);
01340 }
01341
01343 void set_empty_ok() { empty_ok = true; }
01344
01346 Query * as_group(State *state) const;
01347
01351 void destroy() { delete this; }
01352
01353 protected:
01357 ~TermGroup() {
01358 vector<Term*>::const_iterator i;
01359 for (i = terms.begin(); i != terms.end(); ++i) {
01360 delete *i;
01361 }
01362 }
01363 };
01364
01365 Query *
01366 TermGroup::as_group(State *state) const
01367 {
01368 const Xapian::Stopper * stopper = state->get_stopper();
01369 size_t stoplist_size = state->stoplist_size();
01370 bool default_op_is_positional = is_positional(state->default_op());
01371 reprocess:
01372 Query::op default_op = state->default_op();
01373 vector<Query> subqs;
01374 subqs.reserve(terms.size());
01375
01376
01377
01378 const unsigned ENABLE_AUTO_MULTIWORD_SYNONYMS = 1024;
01379 if (state->flags & ENABLE_AUTO_MULTIWORD_SYNONYMS) {
01380
01381 Database db = state->get_database();
01382
01383 string key;
01384 vector<Term*>::const_iterator begin = terms.begin();
01385 vector<Term*>::const_iterator i = begin;
01386 while (i != terms.end()) {
01387 TermIterator synkey(db.synonym_keys_begin((*i)->name));
01388 TermIterator synend(db.synonym_keys_end((*i)->name));
01389 if (synkey == synend) {
01390
01391 if (stopper && (*stopper)((*i)->name)) {
01392 state->add_to_stoplist(*i);
01393 } else {
01394 if (default_op_is_positional)
01395 (*i)->need_positions();
01396 subqs.push_back((*i)->get_query_with_auto_synonyms());
01397 }
01398 begin = ++i;
01399 continue;
01400 }
01401 key.resize(0);
01402 while (i != terms.end()) {
01403 if (!key.empty()) key += ' ';
01404 key += (*i)->name;
01405 ++i;
01406 synkey.skip_to(key);
01407 if (synkey == synend || !startswith(*synkey, key)) break;
01408 }
01409
01410 TermIterator syn, end;
01411 while (true) {
01412 syn = db.synonyms_begin(key);
01413 end = db.synonyms_end(key);
01414 if (syn != end) break;
01415 if (--i == begin) break;
01416 key.resize(key.size() - (*i)->name.size() - 1);
01417 }
01418 if (i == begin) {
01419
01420 if (stopper && (*stopper)((*i)->name)) {
01421 state->add_to_stoplist(*i);
01422 } else {
01423 if (default_op_is_positional)
01424 (*i)->need_positions();
01425 subqs.push_back((*i)->get_query_with_auto_synonyms());
01426 }
01427 begin = ++i;
01428 continue;
01429 }
01430
01431 vector<Query> subqs2;
01432 vector<Term*>::const_iterator j;
01433 for (j = begin; j != i; ++j) {
01434 if (stopper && (*stopper)((*j)->name)) {
01435 state->add_to_stoplist(*j);
01436 } else {
01437 if (default_op_is_positional)
01438 (*i)->need_positions();
01439 subqs2.push_back((*j)->get_query());
01440 }
01441 }
01442 Query q_original_terms;
01443 if (default_op_is_positional) {
01444 q_original_terms = Query(default_op,
01445 subqs2.begin(), subqs2.end(),
01446 subqs2.size() + 9);
01447 } else {
01448 q_original_terms = Query(default_op,
01449 subqs2.begin(), subqs2.end());
01450 }
01451 subqs2.clear();
01452
01453
01454 Xapian::termpos pos = (*begin)->pos;
01455 begin = i;
01456 while (syn != end) {
01457 subqs2.push_back(Query(*syn, 1, pos));
01458 ++syn;
01459 }
01460 Query q_synonym_terms(Query::OP_SYNONYM, subqs2.begin(), subqs2.end());
01461 subqs2.clear();
01462 subqs.push_back(Query(Query::OP_SYNONYM,
01463 q_original_terms, q_synonym_terms));
01464 }
01465 } else {
01466 vector<Term*>::const_iterator i;
01467 for (i = terms.begin(); i != terms.end(); ++i) {
01468 if (stopper && (*stopper)((*i)->name)) {
01469 state->add_to_stoplist(*i);
01470 } else {
01471 if (default_op_is_positional)
01472 (*i)->need_positions();
01473 subqs.push_back((*i)->get_query_with_auto_synonyms());
01474 }
01475 }
01476 }
01477
01478 if (!empty_ok && stopper && subqs.empty() &&
01479 stoplist_size < state->stoplist_size()) {
01480
01481
01482 state->stoplist_resize(stoplist_size);
01483 stopper = NULL;
01484 goto reprocess;
01485 }
01486
01487 Query * q = NULL;
01488 if (!subqs.empty()) {
01489 if (default_op_is_positional) {
01490 q = new Query(default_op, subqs.begin(), subqs.end(),
01491 subqs.size() + 9);
01492 } else {
01493 q = new Query(default_op, subqs.begin(), subqs.end());
01494 }
01495 }
01496 delete this;
01497 return q;
01498 }
01499
01501 class Terms {
01502 vector<Term *> terms;
01503 size_t window;
01504
01514 bool uniform_prefixes;
01515
01519 const list<string> * prefixes;
01520
01522 Query * as_opwindow_query(Query::op op, Xapian::termcount w_delta) const {
01523 Query * q = NULL;
01524 size_t n_terms = terms.size();
01525 Xapian::termcount w = w_delta + terms.size();
01526 if (uniform_prefixes) {
01527 if (prefixes) {
01528 list<string>::const_iterator piter;
01529 for (piter = prefixes->begin(); piter != prefixes->end(); ++piter) {
01530 vector<Query> subqs;
01531 subqs.reserve(n_terms);
01532 vector<Term *>::const_iterator titer;
01533 for (titer = terms.begin(); titer != terms.end(); ++titer) {
01534 Term * t = *titer;
01535 subqs.push_back(Query(t->make_term(*piter), 1, t->pos));
01536 }
01537 add_to_query(q, Query::OP_OR,
01538 Query(op, subqs.begin(), subqs.end(), w));
01539 }
01540 }
01541 } else {
01542 vector<Query> subqs;
01543 subqs.reserve(n_terms);
01544 vector<Term *>::const_iterator titer;
01545 for (titer = terms.begin(); titer != terms.end(); ++titer) {
01546 subqs.push_back((*titer)->get_query());
01547 }
01548 q = new Query(op, subqs.begin(), subqs.end(), w);
01549 }
01550
01551 delete this;
01552 return q;
01553 }
01554
01555 public:
01556 Terms() : window(0), uniform_prefixes(true), prefixes(NULL) { }
01557
01559 void add_positional_term(Term * term) {
01560 const list<string> & term_prefixes = term->prefix_info->prefixes;
01561 if (terms.empty()) {
01562 prefixes = &term_prefixes;
01563 } else if (uniform_prefixes && prefixes != &term_prefixes) {
01564 if (*prefixes != term_prefixes) {
01565 prefixes = NULL;
01566 uniform_prefixes = false;
01567 }
01568 }
01569 term->need_positions();
01570 terms.push_back(term);
01571 }
01572
01573 void adjust_window(size_t alternative_window) {
01574 if (alternative_window > window) window = alternative_window;
01575 }
01576
01578 Query * as_phrase_query() const {
01579 return as_opwindow_query(Query::OP_PHRASE, 0);
01580 }
01581
01583 Query * as_near_query() const {
01584
01585
01586
01587 size_t w = window;
01588 if (w == 0) w = 10;
01589 return as_opwindow_query(Query::OP_NEAR, w - 1);
01590 }
01591
01593 Query * as_adj_query() const {
01594
01595
01596
01597 size_t w = window;
01598 if (w == 0) w = 10;
01599 return as_opwindow_query(Query::OP_PHRASE, w - 1);
01600 }
01601
01605 void destroy() { delete this; }
01606
01607 protected:
01611 ~Terms() {
01612 vector<Term *>::const_iterator t;
01613 for (t = terms.begin(); t != terms.end(); ++t) {
01614 delete *t;
01615 }
01616 }
01617 };
01618
01619 void
01620 Term::as_positional_cjk_term(Terms * terms) const
01621 {
01622
01623 string t;
01624 for (Utf8Iterator it(name); it != Utf8Iterator(); ++it) {
01625 Unicode::append_utf8(t, *it);
01626 Term * c = new Term(state, t, prefix_info, unstemmed, stem, pos);
01627 terms->add_positional_term(c);
01628 t.resize(0);
01629 }
01630
01631
01632
01633 delete this;
01634 }
01635
01636
01637 #define BOOL_OP_TO_QUERY(E, A, OP, B, OP_TXT) \
01638 do {\
01639 if (!A || !B) {\
01640 state->error = "Syntax: <expression> "OP_TXT" <expression>";\
01641 yy_parse_failed(yypParser);\
01642 return;\
01643 }\
01644 E = new Query(OP, *A, *B);\
01645 delete A;\
01646 delete B;\
01647 } while (0)
01648
01649 #line 1650 "queryparser/queryparser_internal.cc"
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662 #ifndef INTERFACE
01663 # define INTERFACE 1
01664 #endif
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699 #define YYCODETYPE unsigned char
01700 #define YYNOCODE 40
01701 #define YYACTIONTYPE unsigned char
01702 #define ParseTOKENTYPE Term *
01703 typedef union {
01704 int yyinit;
01705 ParseTOKENTYPE yy0;
01706 TermGroup * yy14;
01707 Terms * yy32;
01708 Query * yy39;
01709 ProbQuery * yy40;
01710 int yy46;
01711 } YYMINORTYPE;
01712 #ifndef YYSTACKDEPTH
01713 #define YYSTACKDEPTH 100
01714 #endif
01715 #define ParseARG_SDECL State * state;
01716 #define ParseARG_PDECL ,State * state
01717 #define ParseARG_FETCH State * state = yypParser->state
01718 #define ParseARG_STORE yypParser->state = state
01719 #define YYNSTATE 77
01720 #define YYNRULE 56
01721 #define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
01722 #define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
01723 #define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733 #ifndef yytestcase
01734 # define yytestcase(X)
01735 #endif
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784 static const YYACTIONTYPE yy_action[] = {
01785 134, 25, 35, 17, 8, 58, 19, 13, 16, 42,
01786 28, 24, 29, 31, 6, 1, 2, 11, 12, 7,
01787 34, 15, 22, 77, 45, 46, 74, 59, 14, 5,
01788 78, 65, 43, 3, 4, 1, 2, 55, 11, 12,
01789 52, 34, 15, 30, 56, 45, 46, 74, 59, 14,
01790 5, 50, 65, 38, 35, 36, 8, 58, 19, 13,
01791 16, 51, 28, 24, 29, 31, 38, 35, 37, 8,
01792 58, 19, 13, 16, 32, 28, 24, 29, 31, 38,
01793 35, 21, 8, 58, 19, 13, 16, 64, 28, 24,
01794 29, 31, 38, 35, 23, 8, 58, 19, 13, 16,
01795 135, 28, 24, 29, 31, 33, 35, 17, 8, 58,
01796 19, 13, 16, 135, 28, 24, 29, 31, 38, 35,
01797 75, 8, 58, 19, 13, 16, 135, 28, 24, 29,
01798 31, 38, 35, 76, 8, 58, 19, 13, 16, 53,
01799 28, 24, 29, 31, 11, 12, 57, 34, 15, 54,
01800 135, 45, 46, 74, 59, 14, 5, 135, 65, 135,
01801 104, 104, 135, 34, 18, 135, 135, 45, 46, 104,
01802 104, 14, 5, 108, 65, 108, 108, 108, 108, 26,
01803 27, 26, 27, 48, 135, 135, 41, 40, 41, 40,
01804 47, 34, 20, 49, 108, 45, 46, 62, 135, 14,
01805 5, 135, 65, 34, 20, 135, 135, 45, 46, 67,
01806 135, 14, 5, 135, 65, 34, 20, 135, 135, 45,
01807 46, 71, 135, 14, 5, 135, 65, 34, 20, 135,
01808 135, 45, 46, 73, 135, 14, 5, 135, 65, 34,
01809 18, 135, 135, 45, 46, 135, 135, 14, 5, 135,
01810 65, 135, 39, 44, 135, 28, 24, 29, 31, 61,
01811 135, 135, 63, 135, 28, 24, 29, 31, 135, 66,
01812 135, 135, 63, 135, 28, 24, 29, 31, 70, 135,
01813 135, 63, 135, 28, 24, 29, 31, 72, 135, 135,
01814 63, 135, 28, 24, 29, 31, 135, 69, 44, 135,
01815 28, 24, 29, 31, 109, 135, 109, 109, 109, 109,
01816 9, 10, 4, 1, 2, 135, 135, 135, 135, 68,
01817 60, 135, 135, 135, 135, 109,
01818 };
01819 static const YYCODETYPE yy_lookahead[] = {
01820 25, 26, 27, 28, 29, 30, 31, 32, 33, 12,
01821 35, 36, 37, 38, 5, 4, 5, 8, 9, 10,
01822 11, 12, 34, 0, 15, 16, 17, 18, 19, 20,
01823 0, 22, 12, 2, 3, 4, 5, 12, 8, 9,
01824 14, 11, 12, 6, 12, 15, 16, 17, 18, 19,
01825 20, 12, 22, 26, 27, 28, 29, 30, 31, 32,
01826 33, 22, 35, 36, 37, 38, 26, 27, 28, 29,
01827 30, 31, 32, 33, 7, 35, 36, 37, 38, 26,
01828 27, 28, 29, 30, 31, 32, 33, 12, 35, 36,
01829 37, 38, 26, 27, 28, 29, 30, 31, 32, 33,
01830 39, 35, 36, 37, 38, 26, 27, 28, 29, 30,
01831 31, 32, 33, 39, 35, 36, 37, 38, 26, 27,
01832 28, 29, 30, 31, 32, 33, 39, 35, 36, 37,
01833 38, 26, 27, 28, 29, 30, 31, 32, 33, 13,
01834 35, 36, 37, 38, 8, 9, 21, 11, 12, 23,
01835 39, 15, 16, 17, 18, 19, 20, 39, 22, 39,
01836 8, 9, 39, 11, 12, 39, 39, 15, 16, 17,
01837 18, 19, 20, 0, 22, 2, 3, 4, 5, 6,
01838 7, 6, 7, 12, 39, 39, 13, 14, 13, 14,
01839 19, 11, 12, 22, 21, 15, 16, 17, 39, 19,
01840 20, 39, 22, 11, 12, 39, 39, 15, 16, 17,
01841 39, 19, 20, 39, 22, 11, 12, 39, 39, 15,
01842 16, 17, 39, 19, 20, 39, 22, 11, 12, 39,
01843 39, 15, 16, 17, 39, 19, 20, 39, 22, 11,
01844 12, 39, 39, 15, 16, 39, 39, 19, 20, 39,
01845 22, 39, 32, 33, 39, 35, 36, 37, 38, 30,
01846 39, 39, 33, 39, 35, 36, 37, 38, 39, 30,
01847 39, 39, 33, 39, 35, 36, 37, 38, 30, 39,
01848 39, 33, 39, 35, 36, 37, 38, 30, 39, 39,
01849 33, 39, 35, 36, 37, 38, 39, 32, 33, 39,
01850 35, 36, 37, 38, 0, 39, 2, 3, 4, 5,
01851 8, 9, 3, 4, 5, 39, 39, 39, 39, 17,
01852 18, 39, 39, 39, 39, 21,
01853 };
01854 #define YY_SHIFT_USE_DFLT (-4)
01855 #define YY_SHIFT_MAX 34
01856 static const short yy_shift_ofst[] = {
01857 30, 9, 136, 136, 136, 136, 136, 136, 152, 180,
01858 192, 204, 216, 228, 39, 173, 304, 31, 175, 302,
01859 175, 309, 171, 11, 126, 23, -3, 20, 26, 37,
01860 25, 67, 32, 125, 75,
01861 };
01862 #define YY_REDUCE_USE_DFLT (-26)
01863 #define YY_REDUCE_MAX 14
01864 static const short yy_reduce_ofst[] = {
01865 -25, 27, 40, 53, 66, 79, 92, 105, 220, 229,
01866 239, 248, 257, 265, -12,
01867 };
01868 static const YYACTIONTYPE yy_default[] = {
01869 87, 87, 87, 87, 87, 87, 87, 87, 88, 133,
01870 133, 133, 133, 105, 133, 106, 107, 133, 106, 133,
01871 108, 84, 133, 85, 114, 86, 133, 133, 113, 115,
01872 133, 116, 133, 86, 133, 79, 80, 81, 86, 93,
01873 124, 126, 129, 131, 107, 110, 111, 112, 122, 123,
01874 120, 121, 125, 127, 128, 130, 132, 117, 89, 90,
01875 91, 95, 103, 109, 118, 119, 97, 99, 101, 92,
01876 94, 102, 96, 98, 100, 82, 83,
01877 };
01878 #define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0]))
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889
01890 #ifdef YYFALLBACK
01891 static const YYCODETYPE yyFallback[] = {
01892 };
01893 #endif
01894
01895
01896
01897
01898
01899
01900
01901
01902
01903
01904
01905
01906
01907 struct yyStackEntry {
01908 yyStackEntry() {
01909 stateno = 0;
01910 major = 0;
01911 }
01912 yyStackEntry(YYACTIONTYPE stateno_, YYCODETYPE major_, YYMINORTYPE minor_) {
01913 stateno = stateno_;
01914 major = major_;
01915 minor = minor_;
01916 }
01917 YYACTIONTYPE stateno;
01918 YYCODETYPE major;
01919
01920 YYMINORTYPE minor;
01921
01922 };
01923
01924
01925
01926 struct yyParser {
01927 int yyerrcnt;
01928 ParseARG_SDECL
01929 vector<yyStackEntry> yystack;
01930 };
01931 typedef struct yyParser yyParser;
01932
01933 #include "omassert.h"
01934 #include "debuglog.h"
01935
01936 #ifdef XAPIAN_DEBUG_LOG
01937
01938
01939 static const char *const yyTokenName[] = {
01940 "$", "ERROR", "OR", "XOR",
01941 "AND", "NOT", "NEAR", "ADJ",
01942 "LOVE", "HATE", "HATE_AFTER_AND", "SYNONYM",
01943 "TERM", "GROUP_TERM", "PHR_TERM", "WILD_TERM",
01944 "PARTIAL_TERM", "BOOLEAN_FILTER", "RANGE", "QUOTE",
01945 "BRA", "KET", "CJKTERM", "EMPTY_GROUP_OK",
01946 "error", "query", "expr", "prob_expr",
01947 "bool_arg", "prob", "term", "stop_prob",
01948 "stop_term", "compound_term", "phrase", "phrased_term",
01949 "group", "near_expr", "adj_expr",
01950 };
01951
01952
01953
01954 static const char *const yyRuleName[] = {
01955 "query ::= expr",
01956 "query ::=",
01957 "expr ::= prob_expr",
01958 "expr ::= bool_arg AND bool_arg",
01959 "expr ::= bool_arg NOT bool_arg",
01960 "expr ::= bool_arg AND NOT bool_arg",
01961 "expr ::= bool_arg AND HATE_AFTER_AND bool_arg",
01962 "expr ::= bool_arg OR bool_arg",
01963 "expr ::= bool_arg XOR bool_arg",
01964 "bool_arg ::= expr",
01965 "bool_arg ::=",
01966 "prob_expr ::= prob",
01967 "prob_expr ::= term",
01968 "prob ::= RANGE",
01969 "prob ::= stop_prob RANGE",
01970 "prob ::= stop_term stop_term",
01971 "prob ::= prob stop_term",
01972 "prob ::= LOVE term",
01973 "prob ::= stop_prob LOVE term",
01974 "prob ::= HATE term",
01975 "prob ::= stop_prob HATE term",
01976 "prob ::= HATE BOOLEAN_FILTER",
01977 "prob ::= stop_prob HATE BOOLEAN_FILTER",
01978 "prob ::= BOOLEAN_FILTER",
01979 "prob ::= stop_prob BOOLEAN_FILTER",
01980 "prob ::= LOVE BOOLEAN_FILTER",
01981 "prob ::= stop_prob LOVE BOOLEAN_FILTER",
01982 "stop_prob ::= prob",
01983 "stop_prob ::= stop_term",
01984 "stop_term ::= TERM",
01985 "stop_term ::= compound_term",
01986 "term ::= TERM",
01987 "term ::= compound_term",
01988 "compound_term ::= WILD_TERM",
01989 "compound_term ::= PARTIAL_TERM",
01990 "compound_term ::= QUOTE phrase QUOTE",
01991 "compound_term ::= phrased_term",
01992 "compound_term ::= group",
01993 "compound_term ::= near_expr",
01994 "compound_term ::= adj_expr",
01995 "compound_term ::= BRA expr KET",
01996 "compound_term ::= SYNONYM TERM",
01997 "compound_term ::= CJKTERM",
01998 "phrase ::= TERM",
01999 "phrase ::= CJKTERM",
02000 "phrase ::= phrase TERM",
02001 "phrase ::= phrase CJKTERM",
02002 "phrased_term ::= TERM PHR_TERM",
02003 "phrased_term ::= phrased_term PHR_TERM",
02004 "group ::= TERM GROUP_TERM",
02005 "group ::= group GROUP_TERM",
02006 "group ::= group EMPTY_GROUP_OK",
02007 "near_expr ::= TERM NEAR TERM",
02008 "near_expr ::= near_expr NEAR TERM",
02009 "adj_expr ::= TERM ADJ TERM",
02010 "adj_expr ::= adj_expr ADJ TERM",
02011 };
02012
02013
02014
02015
02016
02017 static const char *ParseTokenName(int tokenType){
02018 if( tokenType>=0 && tokenType<(int)(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
02019 return yyTokenName[tokenType];
02020 }
02021 return "Unknown";
02022 }
02023
02024
02025
02026
02027
02028 static const char *ParseRuleName(int ruleNum){
02029 if( ruleNum>=0 && ruleNum<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
02030 return yyRuleName[ruleNum];
02031 }
02032 return "Unknown";
02033 }
02034 #endif
02035
02036
02037
02038
02039
02040
02041
02042
02043
02044
02045
02046
02047
02048 static yyParser *ParseAlloc(){
02049 return new yyParser;
02050 }
02051
02052
02053
02054
02055
02056
02057 static void yy_destructor(
02058 yyParser *yypParser,
02059 YYCODETYPE yymajor,
02060 YYMINORTYPE *yypminor
02061 ){
02062 ParseARG_FETCH;
02063 switch( yymajor ){
02064
02065
02066
02067
02068
02069
02070
02071
02072
02073
02074
02075 case 1:
02076 case 2:
02077 case 3:
02078 case 4:
02079 case 5:
02080 case 6:
02081 case 7:
02082 case 8:
02083 case 9:
02084 case 10:
02085 case 11:
02086 case 12:
02087 case 13:
02088 case 14:
02089 case 15:
02090 case 16:
02091 case 17:
02092 case 18:
02093 case 19:
02094 case 20:
02095 case 21:
02096 case 22:
02097 case 23:
02098 {
02099 #line 1643 "queryparser/queryparser.lemony"
02100 delete (yypminor->yy0);
02101 #line 2102 "queryparser/queryparser_internal.cc"
02102 }
02103 break;
02104 case 26:
02105 case 27:
02106 case 28:
02107 case 30:
02108 case 32:
02109 case 33:
02110 {
02111 #line 1718 "queryparser/queryparser.lemony"
02112 delete (yypminor->yy39);
02113 #line 2114 "queryparser/queryparser_internal.cc"
02114 }
02115 break;
02116 case 29:
02117 case 31:
02118 {
02119 #line 1813 "queryparser/queryparser.lemony"
02120 delete (yypminor->yy40);
02121 #line 2122 "queryparser/queryparser_internal.cc"
02122 }
02123 break;
02124 case 34:
02125 case 35:
02126 case 37:
02127 case 38:
02128 {
02129 #line 2018 "queryparser/queryparser.lemony"
02130 (yypminor->yy32)->destroy();
02131 #line 2132 "queryparser/queryparser_internal.cc"
02132 }
02133 break;
02134 case 36:
02135 {
02136 #line 2062 "queryparser/queryparser.lemony"
02137 (yypminor->yy14)->destroy();
02138 #line 2139 "queryparser/queryparser_internal.cc"
02139 }
02140 break;
02141 default: break;
02142 }
02143 ParseARG_STORE;
02144 }
02145
02146
02147
02148
02149
02150
02151
02152
02153
02154 static int yy_pop_parser_stack(yyParser *pParser){
02155 YYCODETYPE yymajor;
02156 if( pParser->yystack.empty() ) return 0;
02157 yyStackEntry *yytos = &pParser->yystack.back();
02158
02159 LOGLINE(QUERYPARSER, "Popping " << ParseTokenName(yytos->major));
02160 yymajor = (YYCODETYPE)yytos->major;
02161 yy_destructor(pParser, yymajor, &yytos->minor);
02162 pParser->yystack.pop_back();
02163 return yymajor;
02164 }
02165
02166
02167
02168
02169
02170
02171
02172
02173
02174 static void ParseFree(
02175 yyParser *pParser
02176 ){
02177 if( pParser==0 ) return;
02178 while( !pParser->yystack.empty() ) yy_pop_parser_stack(pParser);
02179 delete pParser;
02180 }
02181
02182
02183
02184
02185
02186
02187
02188
02189
02190 static int yy_find_shift_action(
02191 yyParser *pParser,
02192 YYCODETYPE iLookAhead
02193 ){
02194 int i;
02195 int stateno = pParser->yystack.back().stateno;
02196
02197 if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
02198 return yy_default[stateno];
02199 }
02200 Assert( iLookAhead!=YYNOCODE );
02201 i += iLookAhead;
02202 if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
02203 if( iLookAhead>0 ){
02204 #ifdef YYFALLBACK
02205 YYCODETYPE iFallback;
02206 if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
02207 && (iFallback = yyFallback[iLookAhead])!=0 ){
02208 LOGLINE(QUERYPARSER,
02209 "FALLBACK " << ParseTokenName(iLookAhead) << " => " <<
02210 ParseTokenName(iFallback));
02211 return yy_find_shift_action(pParser, iFallback);
02212 }
02213 #endif
02214 #ifdef YYWILDCARD
02215 {
02216 int j = i - iLookAhead + YYWILDCARD;
02217 if( j>=0 && j<YY_SZ_ACTTAB && yy_lookahead[j]==YYWILDCARD ){
02218 LOGLINE(QUERYPARSER,
02219 "WILDCARD " << ParseTokenName(iLookAhead) << " => " <<
02220 ParseTokenName(YYWILDCARD));
02221 return yy_action[j];
02222 }
02223 }
02224 #endif
02225 }
02226 return yy_default[stateno];
02227 }else{
02228 return yy_action[i];
02229 }
02230 }
02231
02232
02233
02234
02235
02236
02237
02238
02239
02240 static int yy_find_reduce_action(
02241 int stateno,
02242 YYCODETYPE iLookAhead
02243 ){
02244 int i;
02245 #ifdef YYERRORSYMBOL
02246 if( stateno>YY_REDUCE_MAX ){
02247 return yy_default[stateno];
02248 }
02249 #else
02250 Assert( stateno<=YY_REDUCE_MAX );
02251 #endif
02252 i = yy_reduce_ofst[stateno];
02253 Assert( i!=YY_REDUCE_USE_DFLT );
02254 Assert( iLookAhead!=YYNOCODE );
02255 i += iLookAhead;
02256 #ifdef YYERRORSYMBOL
02257 if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
02258 return yy_default[stateno];
02259 }
02260 #else
02261 Assert( i>=0 && i<YY_SZ_ACTTAB );
02262 Assert( yy_lookahead[i]==iLookAhead );
02263 #endif
02264 return yy_action[i];
02265 }
02266
02267
02268
02269
02270 static void yy_shift(
02271 yyParser *yypParser,
02272 int yyNewState,
02273 int yyMajor,
02274 YYMINORTYPE *yypMinor
02275 ){
02276
02277
02278
02279
02280 #if 0
02281 #endif
02282 #ifdef XAPIAN_DEBUG_LOG
02283 unsigned i;
02284 LOGLINE(QUERYPARSER, "Shift " << yyNewState);
02285 string stack("Stack:");
02286 for (i = 0; i < yypParser->yystack.size(); i++) {
02287 stack += ' ';
02288 stack += ParseTokenName(yypParser->yystack[i].major);
02289 }
02290 LOGLINE(QUERYPARSER, stack);
02291 #endif
02292 yypParser->yystack.push_back(yyStackEntry(yyNewState, yyMajor, *yypMinor));
02293 }
02294
02295
02296
02297
02298 static const struct {
02299 YYCODETYPE lhs;
02300 unsigned char nrhs;
02301 } yyRuleInfo[] = {
02302 { 25, 1 },
02303 { 25, 0 },
02304 { 26, 1 },
02305 { 26, 3 },
02306 { 26, 3 },
02307 { 26, 4 },
02308 { 26, 4 },
02309 { 26, 3 },
02310 { 26, 3 },
02311 { 28, 1 },
02312 { 28, 0 },
02313 { 27, 1 },
02314 { 27, 1 },
02315 { 29, 1 },
02316 { 29, 2 },
02317 { 29, 2 },
02318 { 29, 2 },
02319 { 29, 2 },
02320 { 29, 3 },
02321 { 29, 2 },
02322 { 29, 3 },
02323 { 29, 2 },
02324 { 29, 3 },
02325 { 29, 1 },
02326 { 29, 2 },
02327 { 29, 2 },
02328 { 29, 3 },
02329 { 31, 1 },
02330 { 31, 1 },
02331 { 32, 1 },
02332 { 32, 1 },
02333 { 30, 1 },
02334 { 30, 1 },
02335 { 33, 1 },
02336 { 33, 1 },
02337 { 33, 3 },
02338 { 33, 1 },
02339 { 33, 1 },
02340 { 33, 1 },
02341 { 33, 1 },
02342 { 33, 3 },
02343 { 33, 2 },
02344 { 33, 1 },
02345 { 34, 1 },
02346 { 34, 1 },
02347 { 34, 2 },
02348 { 34, 2 },
02349 { 35, 2 },
02350 { 35, 2 },
02351 { 36, 2 },
02352 { 36, 2 },
02353 { 36, 2 },
02354 { 37, 3 },
02355 { 37, 3 },
02356 { 38, 3 },
02357 { 38, 3 },
02358 };
02359
02360 static void yy_accept(yyParser*);
02361
02362
02363
02364
02365
02366 static void yy_reduce(
02367 yyParser *yypParser,
02368 int yyruleno
02369 ){
02370 int yygoto;
02371 int yyact;
02372 YYMINORTYPE yygotominor;
02373 yyStackEntry *yymsp;
02374 int yysize;
02375 ParseARG_FETCH;
02376 yymsp = &yypParser->yystack.back();
02377 #ifdef XAPIAN_DEBUG_LOG
02378 LOGLINE(QUERYPARSER, "Reduce [" << ParseRuleName(yyruleno) << "].");
02379 #endif
02380
02381
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392
02393
02394
02395
02396
02397
02398
02399
02400 switch( yyruleno ){
02401
02402
02403
02404
02405
02406
02407
02408
02409 case 0:
02410 #line 1700 "queryparser/queryparser.lemony"
02411 {
02412
02413 if (yymsp[0].minor.yy39) {
02414 state->query = *yymsp[0].minor.yy39;
02415 delete yymsp[0].minor.yy39;
02416 } else {
02417 state->query = Query();
02418 }
02419 }
02420 #line 2421 "queryparser/queryparser_internal.cc"
02421 break;
02422 case 1:
02423 #line 1710 "queryparser/queryparser.lemony"
02424 {
02425
02426 state->query = Query();
02427 }
02428 #line 2429 "queryparser/queryparser_internal.cc"
02429 break;
02430 case 2:
02431 case 9: yytestcase(yyruleno==9);
02432 #line 1721 "queryparser/queryparser.lemony"
02433 { yygotominor.yy39 = yymsp[0].minor.yy39; }
02434 #line 2435 "queryparser/queryparser_internal.cc"
02435 break;
02436 case 3:
02437 #line 1724 "queryparser/queryparser.lemony"
02438 { BOOL_OP_TO_QUERY(yygotominor.yy39, yymsp[-2].minor.yy39, Query::OP_AND, yymsp[0].minor.yy39, "AND"); yy_destructor(yypParser,4,&yymsp[-1].minor);
02439 }
02440 #line 2441 "queryparser/queryparser_internal.cc"
02441 break;
02442 case 4:
02443 #line 1726 "queryparser/queryparser.lemony"
02444 {
02445
02446 if (!yymsp[-2].minor.yy39 && (state->flags & QueryParser::FLAG_PURE_NOT)) {
02447 yymsp[-2].minor.yy39 = new Query("", 1, 0);
02448 }
02449 BOOL_OP_TO_QUERY(yygotominor.yy39, yymsp[-2].minor.yy39, Query::OP_AND_NOT, yymsp[0].minor.yy39, "NOT");
02450 yy_destructor(yypParser,5,&yymsp[-1].minor);
02451 }
02452 #line 2453 "queryparser/queryparser_internal.cc"
02453 break;
02454 case 5:
02455 #line 1735 "queryparser/queryparser.lemony"
02456 { BOOL_OP_TO_QUERY(yygotominor.yy39, yymsp[-3].minor.yy39, Query::OP_AND_NOT, yymsp[0].minor.yy39, "AND NOT"); yy_destructor(yypParser,4,&yymsp[-2].minor);
02457 yy_destructor(yypParser,5,&yymsp[-1].minor);
02458 }
02459 #line 2460 "queryparser/queryparser_internal.cc"
02460 break;
02461 case 6:
02462 #line 1738 "queryparser/queryparser.lemony"
02463 { BOOL_OP_TO_QUERY(yygotominor.yy39, yymsp[-3].minor.yy39, Query::OP_AND_NOT, yymsp[0].minor.yy39, "AND"); yy_destructor(yypParser,4,&yymsp[-2].minor);
02464 yy_destructor(yypParser,10,&yymsp[-1].minor);
02465 }
02466 #line 2467 "queryparser/queryparser_internal.cc"
02467 break;
02468 case 7:
02469 #line 1741 "queryparser/queryparser.lemony"
02470 { BOOL_OP_TO_QUERY(yygotominor.yy39, yymsp[-2].minor.yy39, Query::OP_OR, yymsp[0].minor.yy39, "OR"); yy_destructor(yypParser,2,&yymsp[-1].minor);
02471 }
02472 #line 2473 "queryparser/queryparser_internal.cc"
02473 break;
02474 case 8:
02475 #line 1744 "queryparser/queryparser.lemony"
02476 { BOOL_OP_TO_QUERY(yygotominor.yy39, yymsp[-2].minor.yy39, Query::OP_XOR, yymsp[0].minor.yy39, "XOR"); yy_destructor(yypParser,3,&yymsp[-1].minor);
02477 }
02478 #line 2479 "queryparser/queryparser_internal.cc"
02479 break;
02480 case 10:
02481 #line 1753 "queryparser/queryparser.lemony"
02482 {
02483
02484
02485
02486 yygotominor.yy39 = NULL;
02487 }
02488 #line 2489 "queryparser/queryparser_internal.cc"
02489 break;
02490 case 11:
02491 #line 1765 "queryparser/queryparser.lemony"
02492 {
02493 yygotominor.yy39 = yymsp[0].minor.yy40->query;
02494 yymsp[0].minor.yy40->query = NULL;
02495
02496 if (yymsp[0].minor.yy40->love) {
02497 if (yymsp[0].minor.yy40->love->empty()) {
02498
02499 delete yygotominor.yy39;
02500 yygotominor.yy39 = yymsp[0].minor.yy40->love;
02501 } else if (yygotominor.yy39) {
02502 swap(yygotominor.yy39, yymsp[0].minor.yy40->love);
02503 add_to_query(yygotominor.yy39, Query::OP_AND_MAYBE, yymsp[0].minor.yy40->love);
02504 } else {
02505 yygotominor.yy39 = yymsp[0].minor.yy40->love;
02506 }
02507 yymsp[0].minor.yy40->love = NULL;
02508 }
02509
02510 if (!yymsp[0].minor.yy40->filter.empty()) {
02511 if (yygotominor.yy39) {
02512 add_to_query(yygotominor.yy39, Query::OP_FILTER, yymsp[0].minor.yy40->merge_filters());
02513 } else {
02514
02515 yygotominor.yy39 = new Query(Query::OP_SCALE_WEIGHT, yymsp[0].minor.yy40->merge_filters(), 0.0);
02516 }
02517 }
02518
02519 if (yymsp[0].minor.yy40->hate && !yymsp[0].minor.yy40->hate->empty()) {
02520 if (!yygotominor.yy39) {
02521
02522 yy_parse_failed(yypParser);
02523 return;
02524 }
02525 *yygotominor.yy39 = Query(Query::OP_AND_NOT, *yygotominor.yy39, *yymsp[0].minor.yy40->hate);
02526 }
02527 delete yymsp[0].minor.yy40;
02528 }
02529 #line 2530 "queryparser/queryparser_internal.cc"
02530 break;
02531 case 12:
02532 case 30: yytestcase(yyruleno==30);
02533 case 32: yytestcase(yyruleno==32);
02534 #line 1803 "queryparser/queryparser.lemony"
02535 {
02536 yygotominor.yy39 = yymsp[0].minor.yy39;
02537 }
02538 #line 2539 "queryparser/queryparser_internal.cc"
02539 break;
02540 case 13:
02541 #line 1815 "queryparser/queryparser.lemony"
02542 {
02543 valueno slot = yymsp[0].minor.yy0->pos;
02544 const Query & range = yymsp[0].minor.yy0->as_value_range_query();
02545 yygotominor.yy40 = new ProbQuery;
02546 yygotominor.yy40->add_filter_range(slot, range);
02547 }
02548 #line 2549 "queryparser/queryparser_internal.cc"
02549 break;
02550 case 14:
02551 #line 1822 "queryparser/queryparser.lemony"
02552 {
02553 valueno slot = yymsp[0].minor.yy0->pos;
02554 const Query & range = yymsp[0].minor.yy0->as_value_range_query();
02555 yygotominor.yy40 = yymsp[-1].minor.yy40;
02556 yygotominor.yy40->append_filter_range(slot, range);
02557 }
02558 #line 2559 "queryparser/queryparser_internal.cc"
02559 break;
02560 case 15:
02561 #line 1829 "queryparser/queryparser.lemony"
02562 {
02563 yygotominor.yy40 = new ProbQuery;
02564 yygotominor.yy40->query = yymsp[-1].minor.yy39;
02565 if (yymsp[0].minor.yy39) {
02566 Query::op op = state->default_op();
02567 if (yygotominor.yy40->query && is_positional(op)) {
02568
02569
02570
02571 Query * subqs[2] = { yygotominor.yy40->query, yymsp[0].minor.yy39 };
02572 *(yygotominor.yy40->query) = Query(op, subqs, subqs + 2, 11);
02573 delete yymsp[0].minor.yy39;
02574 } else {
02575 add_to_query(yygotominor.yy40->query, op, yymsp[0].minor.yy39);
02576 }
02577 }
02578 }
02579 #line 2580 "queryparser/queryparser_internal.cc"
02580 break;
02581 case 16:
02582 #line 1847 "queryparser/queryparser.lemony"
02583 {
02584 yygotominor.yy40 = yymsp[-1].minor.yy40;
02585
02586 if (yymsp[0].minor.yy39) add_to_query(yygotominor.yy40->query, state->default_op(), yymsp[0].minor.yy39);
02587 }
02588 #line 2589 "queryparser/queryparser_internal.cc"
02589 break;
02590 case 17:
02591 #line 1853 "queryparser/queryparser.lemony"
02592 {
02593 yygotominor.yy40 = new ProbQuery;
02594 if (state->default_op() == Query::OP_AND) {
02595 yygotominor.yy40->query = yymsp[0].minor.yy39;
02596 } else {
02597 yygotominor.yy40->love = yymsp[0].minor.yy39;
02598 }
02599 yy_destructor(yypParser,8,&yymsp[-1].minor);
02600 }
02601 #line 2602 "queryparser/queryparser_internal.cc"
02602 break;
02603 case 18:
02604 #line 1862 "queryparser/queryparser.lemony"
02605 {
02606 yygotominor.yy40 = yymsp[-2].minor.yy40;
02607 if (state->default_op() == Query::OP_AND) {
02608
02609
02610
02611 add_to_query(yygotominor.yy40->query, Query::OP_AND, yymsp[0].minor.yy39);
02612 } else {
02613 add_to_query(yygotominor.yy40->love, Query::OP_AND, yymsp[0].minor.yy39);
02614 }
02615 yy_destructor(yypParser,8,&yymsp[-1].minor);
02616 }
02617 #line 2618 "queryparser/queryparser_internal.cc"
02618 break;
02619 case 19:
02620 #line 1874 "queryparser/queryparser.lemony"
02621 {
02622 yygotominor.yy40 = new ProbQuery;
02623 yygotominor.yy40->hate = yymsp[0].minor.yy39;
02624 yy_destructor(yypParser,9,&yymsp[-1].minor);
02625 }
02626 #line 2627 "queryparser/queryparser_internal.cc"
02627 break;
02628 case 20:
02629 #line 1879 "queryparser/queryparser.lemony"
02630 {
02631 yygotominor.yy40 = yymsp[-2].minor.yy40;
02632 add_to_query(yygotominor.yy40->hate, Query::OP_OR, yymsp[0].minor.yy39);
02633 yy_destructor(yypParser,9,&yymsp[-1].minor);
02634 }
02635 #line 2636 "queryparser/queryparser_internal.cc"
02636 break;
02637 case 21:
02638 #line 1884 "queryparser/queryparser.lemony"
02639 {
02640 yygotominor.yy40 = new ProbQuery;
02641 yygotominor.yy40->hate = new Query(yymsp[0].minor.yy0->get_query());
02642 delete yymsp[0].minor.yy0;
02643 yy_destructor(yypParser,9,&yymsp[-1].minor);
02644 }
02645 #line 2646 "queryparser/queryparser_internal.cc"
02646 break;
02647 case 22:
02648 #line 1890 "queryparser/queryparser.lemony"
02649 {
02650 yygotominor.yy40 = yymsp[-2].minor.yy40;
02651 add_to_query(yygotominor.yy40->hate, Query::OP_OR, yymsp[0].minor.yy0->get_query());
02652 delete yymsp[0].minor.yy0;
02653 yy_destructor(yypParser,9,&yymsp[-1].minor);
02654 }
02655 #line 2656 "queryparser/queryparser_internal.cc"
02656 break;
02657 case 23:
02658 #line 1896 "queryparser/queryparser.lemony"
02659 {
02660 yygotominor.yy40 = new ProbQuery;
02661 yygotominor.yy40->add_filter(yymsp[0].minor.yy0->get_filter_group_id(), yymsp[0].minor.yy0->get_query());
02662 delete yymsp[0].minor.yy0;
02663 }
02664 #line 2665 "queryparser/queryparser_internal.cc"
02665 break;
02666 case 24:
02667 #line 1902 "queryparser/queryparser.lemony"
02668 {
02669 yygotominor.yy40 = yymsp[-1].minor.yy40;
02670 yygotominor.yy40->append_filter(yymsp[0].minor.yy0->get_filter_group_id(), yymsp[0].minor.yy0->get_query());
02671 delete yymsp[0].minor.yy0;
02672 }
02673 #line 2674 "queryparser/queryparser_internal.cc"
02674 break;
02675 case 25:
02676 #line 1908 "queryparser/queryparser.lemony"
02677 {
02678
02679 yygotominor.yy40 = new ProbQuery;
02680 yygotominor.yy40->filter[yymsp[0].minor.yy0->get_filter_group_id()] = yymsp[0].minor.yy0->get_query();
02681 delete yymsp[0].minor.yy0;
02682 yy_destructor(yypParser,8,&yymsp[-1].minor);
02683 }
02684 #line 2685 "queryparser/queryparser_internal.cc"
02685 break;
02686 case 26:
02687 #line 1915 "queryparser/queryparser.lemony"
02688 {
02689
02690 yygotominor.yy40 = yymsp[-2].minor.yy40;
02691
02692 Query & q = yygotominor.yy40->filter[yymsp[0].minor.yy0->get_filter_group_id()];
02693 q = Query(Query::OP_OR, q, yymsp[0].minor.yy0->get_query());
02694 delete yymsp[0].minor.yy0;
02695 yy_destructor(yypParser,8,&yymsp[-1].minor);
02696 }
02697 #line 2698 "queryparser/queryparser_internal.cc"
02698 break;
02699 case 27:
02700 #line 1930 "queryparser/queryparser.lemony"
02701 { yygotominor.yy40 = yymsp[0].minor.yy40; }
02702 #line 2703 "queryparser/queryparser_internal.cc"
02703 break;
02704 case 28:
02705 #line 1932 "queryparser/queryparser.lemony"
02706 {
02707 yygotominor.yy40 = new ProbQuery;
02708 yygotominor.yy40->query = yymsp[0].minor.yy39;
02709 }
02710 #line 2711 "queryparser/queryparser_internal.cc"
02711 break;
02712 case 29:
02713 #line 1946 "queryparser/queryparser.lemony"
02714 {
02715 if (state->is_stopword(yymsp[0].minor.yy0)) {
02716 yygotominor.yy39 = NULL;
02717 state->add_to_stoplist(yymsp[0].minor.yy0);
02718 } else {
02719 yygotominor.yy39 = new Query(yymsp[0].minor.yy0->get_query_with_auto_synonyms());
02720 }
02721 delete yymsp[0].minor.yy0;
02722 }
02723 #line 2724 "queryparser/queryparser_internal.cc"
02724 break;
02725 case 31:
02726 #line 1965 "queryparser/queryparser.lemony"
02727 {
02728 yygotominor.yy39 = new Query(yymsp[0].minor.yy0->get_query_with_auto_synonyms());
02729 delete yymsp[0].minor.yy0;
02730 }
02731 #line 2732 "queryparser/queryparser_internal.cc"
02732 break;
02733 case 33:
02734 #line 1982 "queryparser/queryparser.lemony"
02735 { yygotominor.yy39 = yymsp[0].minor.yy0->as_wildcarded_query(state); }
02736 #line 2737 "queryparser/queryparser_internal.cc"
02737 break;
02738 case 34:
02739 #line 1985 "queryparser/queryparser.lemony"
02740 { yygotominor.yy39 = yymsp[0].minor.yy0->as_partial_query(state); }
02741 #line 2742 "queryparser/queryparser_internal.cc"
02742 break;
02743 case 35:
02744 #line 1988 "queryparser/queryparser.lemony"
02745 { yygotominor.yy39 = yymsp[-1].minor.yy32->as_phrase_query(); yy_destructor(yypParser,19,&yymsp[-2].minor);
02746 yy_destructor(yypParser,19,&yymsp[0].minor);
02747 }
02748 #line 2749 "queryparser/queryparser_internal.cc"
02749 break;
02750 case 36:
02751 #line 1991 "queryparser/queryparser.lemony"
02752 { yygotominor.yy39 = yymsp[0].minor.yy32->as_phrase_query(); }
02753 #line 2754 "queryparser/queryparser_internal.cc"
02754 break;
02755 case 37:
02756 #line 1994 "queryparser/queryparser.lemony"
02757 { yygotominor.yy39 = yymsp[0].minor.yy14->as_group(state); }
02758 #line 2759 "queryparser/queryparser_internal.cc"
02759 break;
02760 case 38:
02761 #line 1997 "queryparser/queryparser.lemony"
02762 { yygotominor.yy39 = yymsp[0].minor.yy32->as_near_query(); }
02763 #line 2764 "queryparser/queryparser_internal.cc"
02764 break;
02765 case 39:
02766 #line 2000 "queryparser/queryparser.lemony"
02767 { yygotominor.yy39 = yymsp[0].minor.yy32->as_adj_query(); }
02768 #line 2769 "queryparser/queryparser_internal.cc"
02769 break;
02770 case 40:
02771 #line 2003 "queryparser/queryparser.lemony"
02772 { yygotominor.yy39 = yymsp[-1].minor.yy39; yy_destructor(yypParser,20,&yymsp[-2].minor);
02773 yy_destructor(yypParser,21,&yymsp[0].minor);
02774 }
02775 #line 2776 "queryparser/queryparser_internal.cc"
02776 break;
02777 case 41:
02778 #line 2005 "queryparser/queryparser.lemony"
02779 {
02780 yygotominor.yy39 = new Query(yymsp[0].minor.yy0->get_query_with_synonyms());
02781 delete yymsp[0].minor.yy0;
02782 yy_destructor(yypParser,11,&yymsp[-1].minor);
02783 }
02784 #line 2785 "queryparser/queryparser_internal.cc"
02785 break;
02786 case 42:
02787 #line 2010 "queryparser/queryparser.lemony"
02788 {
02789 { yygotominor.yy39 = yymsp[0].minor.yy0->as_cjk_query(); }
02790 }
02791 #line 2792 "queryparser/queryparser_internal.cc"
02792 break;
02793 case 43:
02794 #line 2020 "queryparser/queryparser.lemony"
02795 {
02796 yygotominor.yy32 = new Terms;
02797 yygotominor.yy32->add_positional_term(yymsp[0].minor.yy0);
02798 }
02799 #line 2800 "queryparser/queryparser_internal.cc"
02800 break;
02801 case 44:
02802 #line 2025 "queryparser/queryparser.lemony"
02803 {
02804 yygotominor.yy32 = new Terms;
02805 yymsp[0].minor.yy0->as_positional_cjk_term(yygotominor.yy32);
02806 }
02807 #line 2808 "queryparser/queryparser_internal.cc"
02808 break;
02809 case 45:
02810 case 48: yytestcase(yyruleno==48);
02811 #line 2030 "queryparser/queryparser.lemony"
02812 {
02813 yygotominor.yy32 = yymsp[-1].minor.yy32;
02814 yygotominor.yy32->add_positional_term(yymsp[0].minor.yy0);
02815 }
02816 #line 2817 "queryparser/queryparser_internal.cc"
02817 break;
02818 case 46:
02819 #line 2035 "queryparser/queryparser.lemony"
02820 {
02821 yygotominor.yy32 = yymsp[-1].minor.yy32;
02822 yymsp[0].minor.yy0->as_positional_cjk_term(yygotominor.yy32);
02823 }
02824 #line 2825 "queryparser/queryparser_internal.cc"
02825 break;
02826 case 47:
02827 #line 2047 "queryparser/queryparser.lemony"
02828 {
02829 yygotominor.yy32 = new Terms;
02830 yygotominor.yy32->add_positional_term(yymsp[-1].minor.yy0);
02831 yygotominor.yy32->add_positional_term(yymsp[0].minor.yy0);
02832 }
02833 #line 2834 "queryparser/queryparser_internal.cc"
02834 break;
02835 case 49:
02836 #line 2064 "queryparser/queryparser.lemony"
02837 {
02838 yygotominor.yy14 = new TermGroup;
02839 yygotominor.yy14->add_term(yymsp[-1].minor.yy0);
02840 yygotominor.yy14->add_term(yymsp[0].minor.yy0);
02841 }
02842 #line 2843 "queryparser/queryparser_internal.cc"
02843 break;
02844 case 50:
02845 #line 2070 "queryparser/queryparser.lemony"
02846 {
02847 yygotominor.yy14 = yymsp[-1].minor.yy14;
02848 yygotominor.yy14->add_term(yymsp[0].minor.yy0);
02849 }
02850 #line 2851 "queryparser/queryparser_internal.cc"
02851 break;
02852 case 51:
02853 #line 2075 "queryparser/queryparser.lemony"
02854 {
02855 yygotominor.yy14 = yymsp[-1].minor.yy14;
02856 yygotominor.yy14->set_empty_ok();
02857 yy_destructor(yypParser,23,&yymsp[0].minor);
02858 }
02859 #line 2860 "queryparser/queryparser_internal.cc"
02860 break;
02861 case 52:
02862 case 54: yytestcase(yyruleno==54);
02863 #line 2086 "queryparser/queryparser.lemony"
02864 {
02865 yygotominor.yy32 = new Terms;
02866 yygotominor.yy32->add_positional_term(yymsp[-2].minor.yy0);
02867 yygotominor.yy32->add_positional_term(yymsp[0].minor.yy0);
02868 if (yymsp[-1].minor.yy0) {
02869 yygotominor.yy32->adjust_window(yymsp[-1].minor.yy0->get_termpos());
02870 delete yymsp[-1].minor.yy0;
02871 }
02872 }
02873 #line 2874 "queryparser/queryparser_internal.cc"
02874 break;
02875 case 53:
02876 case 55: yytestcase(yyruleno==55);
02877 #line 2096 "queryparser/queryparser.lemony"
02878 {
02879 yygotominor.yy32 = yymsp[-2].minor.yy32;
02880 yygotominor.yy32->add_positional_term(yymsp[0].minor.yy0);
02881 if (yymsp[-1].minor.yy0) {
02882 yygotominor.yy32->adjust_window(yymsp[-1].minor.yy0->get_termpos());
02883 delete yymsp[-1].minor.yy0;
02884 }
02885 }
02886 #line 2887 "queryparser/queryparser_internal.cc"
02887 break;
02888 default:
02889 break;
02890 }
02891 yygoto = yyRuleInfo[yyruleno].lhs;
02892 yysize = yyRuleInfo[yyruleno].nrhs;
02893 yypParser->yystack.resize(yypParser->yystack.size() - yysize);
02894 yyact = yy_find_reduce_action(yypParser->yystack.back().stateno,(YYCODETYPE)yygoto);
02895 if( yyact < YYNSTATE ){
02896 yy_shift(yypParser,yyact,yygoto,&yygotominor);
02897 }else{
02898 Assert( yyact == YYNSTATE + YYNRULE + 1 );
02899 yy_accept(yypParser);
02900 }
02901 }
02902
02903
02904
02905
02906 #ifndef YYNOERRORRECOVERY
02907 static void yy_parse_failed(
02908 yyParser *yypParser
02909 ){
02910 ParseARG_FETCH;
02911 LOGLINE(QUERYPARSER, "Fail!");
02912 while( !yypParser->yystack.empty() ) yy_pop_parser_stack(yypParser);
02913
02914
02915 #line 1647 "queryparser/queryparser.lemony"
02916
02917
02918 if (!state->error) state->error = "parse error";
02919 #line 2920 "queryparser/queryparser_internal.cc"
02920 ParseARG_STORE;
02921 }
02922 #endif
02923
02924
02925
02926
02927 static void yy_syntax_error(
02928 yyParser *yypParser,
02929 int yymajor,
02930 YYMINORTYPE yyminor
02931 ){
02932 ParseARG_FETCH;
02933 (void)yymajor;
02934 (void)yyminor;
02935 #define TOKEN (yyminor.yy0)
02936 #line 1652 "queryparser/queryparser.lemony"
02937
02938 yy_parse_failed(yypParser);
02939 #line 2940 "queryparser/queryparser_internal.cc"
02940 ParseARG_STORE;
02941 }
02942
02943
02944
02945
02946 static void yy_accept(
02947 yyParser *yypParser
02948 ){
02949 ParseARG_FETCH;
02950 LOGLINE(QUERYPARSER, "Accept!");
02951 while( !yypParser->yystack.empty() ) yy_pop_parser_stack(yypParser);
02952
02953
02954 ParseARG_STORE;
02955 }
02956
02957
02958
02959
02960
02961
02962
02963
02964
02965
02966
02967
02968
02969
02970
02971
02972
02973
02974
02975
02976 static void Parse(
02977 yyParser *yypParser,
02978 int yymajor,
02979 ParseTOKENTYPE yyminor
02980 ParseARG_PDECL
02981 ){
02982 YYMINORTYPE yyminorunion;
02983 int yyact;
02984 int yyendofinput;
02985 #ifdef YYERRORSYMBOL
02986 int yyerrorhit = 0;
02987 #endif
02988
02989
02990 if( yypParser->yystack.empty() ){
02991 yypParser->yystack.push_back(yyStackEntry());
02992 yypParser->yyerrcnt = -1;
02993 }
02994 yyminorunion.yy0 = yyminor;
02995 yyendofinput = (yymajor==0);
02996 ParseARG_STORE;
02997
02998 LOGLINE(QUERYPARSER, "Input " << ParseTokenName(yymajor) << " " <<
02999 (yyminor ? yyminor->name : "<<null>>"));
03000
03001 do{
03002 yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
03003 if( yyact<YYNSTATE ){
03004 Assert( !yyendofinput );
03005 yy_shift(yypParser,yyact,yymajor,&yyminorunion);
03006 yypParser->yyerrcnt--;
03007 yymajor = YYNOCODE;
03008 }else if( yyact < YYNSTATE + YYNRULE ){
03009 yy_reduce(yypParser,yyact-YYNSTATE);
03010 }else{
03011 Assert( yyact == YY_ERROR_ACTION );
03012 #ifdef YYERRORSYMBOL
03013 int yymx;
03014 #endif
03015 LOGLINE(QUERYPARSER, "Syntax Error!");
03016 #ifdef YYERRORSYMBOL
03017
03018
03019
03020
03021
03022
03023
03024
03025
03026
03027
03028
03029
03030
03031
03032
03033
03034
03035
03036 if( yypParser->yyerrcnt<0 ){
03037 yy_syntax_error(yypParser,yymajor,yyminorunion);
03038 }
03039 yymx = yypParser->yystack.back().major;
03040 if( yymx==YYERRORSYMBOL || yyerrorhit ){
03041 LOGLINE(QUERYPARSER, "Discard input token " << ParseTokenName(yymajor));
03042 yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion);
03043 yymajor = YYNOCODE;
03044 }else{
03045 while(
03046 !yypParser->yystack.empty() &&
03047 yymx != YYERRORSYMBOL &&
03048 (yyact = yy_find_reduce_action(
03049 yypParser->yystack.back().stateno,
03050 YYERRORSYMBOL)) >= YYNSTATE
03051 ){
03052 yy_pop_parser_stack(yypParser);
03053 }
03054 if( yypParser->yystack.empty() || yymajor==0 ){
03055 yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion);
03056 yy_parse_failed(yypParser);
03057 yymajor = YYNOCODE;
03058 }else if( yymx!=YYERRORSYMBOL ){
03059 YYMINORTYPE u2;
03060 u2.YYERRSYMDT = 0;
03061 yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
03062 }
03063 }
03064 yypParser->yyerrcnt = 3;
03065 yyerrorhit = 1;
03066 #elif defined(YYNOERRORRECOVERY)
03067
03068
03069
03070
03071
03072
03073
03074 yy_syntax_error(yypParser,yymajor,yyminorunion);
03075 yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
03076 yymajor = YYNOCODE;
03077
03078 #else
03079
03080
03081
03082
03083
03084
03085
03086
03087
03088 if( yypParser->yyerrcnt<=0 ){
03089 yy_syntax_error(yypParser,yymajor,yyminorunion);
03090 }
03091 yypParser->yyerrcnt = 3;
03092 yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
03093 if( yyendofinput ){
03094 yy_parse_failed(yypParser);
03095 }
03096 yymajor = YYNOCODE;
03097 #endif
03098 }
03099 }while( yymajor!=YYNOCODE && !yypParser->yystack.empty() );
03100 return;
03101 }
03102
03103