isomorfeus-ferret 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (222) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +612 -0
  3. data/README.md +44 -0
  4. data/ext/isomorfeus_ferret_ext/benchmark.c +223 -0
  5. data/ext/isomorfeus_ferret_ext/benchmark.h +45 -0
  6. data/ext/isomorfeus_ferret_ext/benchmarks_all.h +25 -0
  7. data/ext/isomorfeus_ferret_ext/bm_bitvector.c +123 -0
  8. data/ext/isomorfeus_ferret_ext/bm_hash.c +118 -0
  9. data/ext/isomorfeus_ferret_ext/bm_micro_string.c +40 -0
  10. data/ext/isomorfeus_ferret_ext/bm_store.c +93 -0
  11. data/ext/isomorfeus_ferret_ext/email.rl +21 -0
  12. data/ext/isomorfeus_ferret_ext/extconf.rb +5 -0
  13. data/ext/isomorfeus_ferret_ext/fio_tmpfile.h +53 -0
  14. data/ext/isomorfeus_ferret_ext/frb_analysis.c +2577 -0
  15. data/ext/isomorfeus_ferret_ext/frb_index.c +3457 -0
  16. data/ext/isomorfeus_ferret_ext/frb_lang.c +9 -0
  17. data/ext/isomorfeus_ferret_ext/frb_lang.h +17 -0
  18. data/ext/isomorfeus_ferret_ext/frb_qparser.c +629 -0
  19. data/ext/isomorfeus_ferret_ext/frb_search.c +4460 -0
  20. data/ext/isomorfeus_ferret_ext/frb_store.c +515 -0
  21. data/ext/isomorfeus_ferret_ext/frb_threading.h +30 -0
  22. data/ext/isomorfeus_ferret_ext/frb_utils.c +1127 -0
  23. data/ext/isomorfeus_ferret_ext/frt_analysis.c +1644 -0
  24. data/ext/isomorfeus_ferret_ext/frt_analysis.h +247 -0
  25. data/ext/isomorfeus_ferret_ext/frt_array.c +124 -0
  26. data/ext/isomorfeus_ferret_ext/frt_array.h +54 -0
  27. data/ext/isomorfeus_ferret_ext/frt_bitvector.c +95 -0
  28. data/ext/isomorfeus_ferret_ext/frt_bitvector.h +586 -0
  29. data/ext/isomorfeus_ferret_ext/frt_compound_io.c +374 -0
  30. data/ext/isomorfeus_ferret_ext/frt_config.h +44 -0
  31. data/ext/isomorfeus_ferret_ext/frt_document.c +134 -0
  32. data/ext/isomorfeus_ferret_ext/frt_document.h +52 -0
  33. data/ext/isomorfeus_ferret_ext/frt_except.c +95 -0
  34. data/ext/isomorfeus_ferret_ext/frt_except.h +188 -0
  35. data/ext/isomorfeus_ferret_ext/frt_field_index.c +233 -0
  36. data/ext/isomorfeus_ferret_ext/frt_field_index.h +42 -0
  37. data/ext/isomorfeus_ferret_ext/frt_filter.c +157 -0
  38. data/ext/isomorfeus_ferret_ext/frt_fs_store.c +502 -0
  39. data/ext/isomorfeus_ferret_ext/frt_global.c +427 -0
  40. data/ext/isomorfeus_ferret_ext/frt_global.h +290 -0
  41. data/ext/isomorfeus_ferret_ext/frt_hash.c +518 -0
  42. data/ext/isomorfeus_ferret_ext/frt_hash.h +466 -0
  43. data/ext/isomorfeus_ferret_ext/frt_hashset.c +191 -0
  44. data/ext/isomorfeus_ferret_ext/frt_hashset.h +206 -0
  45. data/ext/isomorfeus_ferret_ext/frt_helper.c +62 -0
  46. data/ext/isomorfeus_ferret_ext/frt_helper.h +13 -0
  47. data/ext/isomorfeus_ferret_ext/frt_ind.c +353 -0
  48. data/ext/isomorfeus_ferret_ext/frt_ind.h +54 -0
  49. data/ext/isomorfeus_ferret_ext/frt_index.c +6377 -0
  50. data/ext/isomorfeus_ferret_ext/frt_index.h +880 -0
  51. data/ext/isomorfeus_ferret_ext/frt_lang.c +104 -0
  52. data/ext/isomorfeus_ferret_ext/frt_lang.h +44 -0
  53. data/ext/isomorfeus_ferret_ext/frt_mempool.c +87 -0
  54. data/ext/isomorfeus_ferret_ext/frt_mempool.h +33 -0
  55. data/ext/isomorfeus_ferret_ext/frt_multimapper.c +349 -0
  56. data/ext/isomorfeus_ferret_ext/frt_multimapper.h +52 -0
  57. data/ext/isomorfeus_ferret_ext/frt_posh.c +1006 -0
  58. data/ext/isomorfeus_ferret_ext/frt_posh.h +973 -0
  59. data/ext/isomorfeus_ferret_ext/frt_priorityqueue.c +147 -0
  60. data/ext/isomorfeus_ferret_ext/frt_priorityqueue.h +147 -0
  61. data/ext/isomorfeus_ferret_ext/frt_q_boolean.c +1612 -0
  62. data/ext/isomorfeus_ferret_ext/frt_q_const_score.c +157 -0
  63. data/ext/isomorfeus_ferret_ext/frt_q_filtered_query.c +209 -0
  64. data/ext/isomorfeus_ferret_ext/frt_q_fuzzy.c +281 -0
  65. data/ext/isomorfeus_ferret_ext/frt_q_match_all.c +147 -0
  66. data/ext/isomorfeus_ferret_ext/frt_q_multi_term.c +672 -0
  67. data/ext/isomorfeus_ferret_ext/frt_q_parser.c +3084 -0
  68. data/ext/isomorfeus_ferret_ext/frt_q_phrase.c +1182 -0
  69. data/ext/isomorfeus_ferret_ext/frt_q_prefix.c +98 -0
  70. data/ext/isomorfeus_ferret_ext/frt_q_range.c +665 -0
  71. data/ext/isomorfeus_ferret_ext/frt_q_span.c +2386 -0
  72. data/ext/isomorfeus_ferret_ext/frt_q_term.c +311 -0
  73. data/ext/isomorfeus_ferret_ext/frt_q_wildcard.c +166 -0
  74. data/ext/isomorfeus_ferret_ext/frt_ram_store.c +460 -0
  75. data/ext/isomorfeus_ferret_ext/frt_scanner.c +899 -0
  76. data/ext/isomorfeus_ferret_ext/frt_scanner.h +28 -0
  77. data/ext/isomorfeus_ferret_ext/frt_scanner_mb.c +6705 -0
  78. data/ext/isomorfeus_ferret_ext/frt_scanner_utf8.c +4419 -0
  79. data/ext/isomorfeus_ferret_ext/frt_search.c +1824 -0
  80. data/ext/isomorfeus_ferret_ext/frt_search.h +924 -0
  81. data/ext/isomorfeus_ferret_ext/frt_similarity.c +150 -0
  82. data/ext/isomorfeus_ferret_ext/frt_similarity.h +79 -0
  83. data/ext/isomorfeus_ferret_ext/frt_sort.c +796 -0
  84. data/ext/isomorfeus_ferret_ext/frt_stopwords.c +395 -0
  85. data/ext/isomorfeus_ferret_ext/frt_store.c +680 -0
  86. data/ext/isomorfeus_ferret_ext/frt_store.h +789 -0
  87. data/ext/isomorfeus_ferret_ext/frt_term_vectors.c +72 -0
  88. data/ext/isomorfeus_ferret_ext/frt_threading.h +23 -0
  89. data/ext/isomorfeus_ferret_ext/frt_win32.h +54 -0
  90. data/ext/isomorfeus_ferret_ext/isomorfeus_ferret.c +409 -0
  91. data/ext/isomorfeus_ferret_ext/isomorfeus_ferret.h +95 -0
  92. data/ext/isomorfeus_ferret_ext/libstemmer.c +93 -0
  93. data/ext/isomorfeus_ferret_ext/libstemmer.h +73 -0
  94. data/ext/isomorfeus_ferret_ext/q_parser.y +1366 -0
  95. data/ext/isomorfeus_ferret_ext/scanner.h +28 -0
  96. data/ext/isomorfeus_ferret_ext/scanner.in +43 -0
  97. data/ext/isomorfeus_ferret_ext/scanner.rl +84 -0
  98. data/ext/isomorfeus_ferret_ext/scanner_mb.rl +200 -0
  99. data/ext/isomorfeus_ferret_ext/scanner_utf8.rl +85 -0
  100. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_danish.c +324 -0
  101. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_danish.h +7 -0
  102. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_dutch.c +610 -0
  103. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_dutch.h +6 -0
  104. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_english.c +1104 -0
  105. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_english.h +6 -0
  106. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_finnish.c +749 -0
  107. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_finnish.h +7 -0
  108. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_french.c +1233 -0
  109. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_french.h +6 -0
  110. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_german.c +490 -0
  111. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_german.h +6 -0
  112. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_hungarian.c +1217 -0
  113. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_hungarian.h +7 -0
  114. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_italian.c +1052 -0
  115. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_italian.h +6 -0
  116. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_norwegian.c +283 -0
  117. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_norwegian.h +6 -0
  118. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_porter.c +735 -0
  119. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_porter.h +6 -0
  120. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_portuguese.c +1003 -0
  121. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_portuguese.h +7 -0
  122. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_spanish.c +1079 -0
  123. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_spanish.h +6 -0
  124. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_swedish.c +293 -0
  125. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_swedish.h +6 -0
  126. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_2_romanian.c +984 -0
  127. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_2_romanian.h +6 -0
  128. data/ext/isomorfeus_ferret_ext/stem_KOI8_R_russian.c +686 -0
  129. data/ext/isomorfeus_ferret_ext/stem_KOI8_R_russian.h +6 -0
  130. data/ext/isomorfeus_ferret_ext/stem_UTF_8_danish.c +325 -0
  131. data/ext/isomorfeus_ferret_ext/stem_UTF_8_danish.h +6 -0
  132. data/ext/isomorfeus_ferret_ext/stem_UTF_8_dutch.c +620 -0
  133. data/ext/isomorfeus_ferret_ext/stem_UTF_8_dutch.h +6 -0
  134. data/ext/isomorfeus_ferret_ext/stem_UTF_8_english.c +1111 -0
  135. data/ext/isomorfeus_ferret_ext/stem_UTF_8_english.h +6 -0
  136. data/ext/isomorfeus_ferret_ext/stem_UTF_8_finnish.c +754 -0
  137. data/ext/isomorfeus_ferret_ext/stem_UTF_8_finnish.h +6 -0
  138. data/ext/isomorfeus_ferret_ext/stem_UTF_8_french.c +1242 -0
  139. data/ext/isomorfeus_ferret_ext/stem_UTF_8_french.h +6 -0
  140. data/ext/isomorfeus_ferret_ext/stem_UTF_8_german.c +495 -0
  141. data/ext/isomorfeus_ferret_ext/stem_UTF_8_german.h +6 -0
  142. data/ext/isomorfeus_ferret_ext/stem_UTF_8_hungarian.c +1220 -0
  143. data/ext/isomorfeus_ferret_ext/stem_UTF_8_hungarian.h +6 -0
  144. data/ext/isomorfeus_ferret_ext/stem_UTF_8_italian.c +1059 -0
  145. data/ext/isomorfeus_ferret_ext/stem_UTF_8_italian.h +6 -0
  146. data/ext/isomorfeus_ferret_ext/stem_UTF_8_norwegian.c +285 -0
  147. data/ext/isomorfeus_ferret_ext/stem_UTF_8_norwegian.h +6 -0
  148. data/ext/isomorfeus_ferret_ext/stem_UTF_8_porter.c +741 -0
  149. data/ext/isomorfeus_ferret_ext/stem_UTF_8_porter.h +6 -0
  150. data/ext/isomorfeus_ferret_ext/stem_UTF_8_portuguese.c +1009 -0
  151. data/ext/isomorfeus_ferret_ext/stem_UTF_8_portuguese.h +6 -0
  152. data/ext/isomorfeus_ferret_ext/stem_UTF_8_romanian.c +990 -0
  153. data/ext/isomorfeus_ferret_ext/stem_UTF_8_romanian.h +6 -0
  154. data/ext/isomorfeus_ferret_ext/stem_UTF_8_russian.c +680 -0
  155. data/ext/isomorfeus_ferret_ext/stem_UTF_8_russian.h +6 -0
  156. data/ext/isomorfeus_ferret_ext/stem_UTF_8_spanish.c +1083 -0
  157. data/ext/isomorfeus_ferret_ext/stem_UTF_8_spanish.h +6 -0
  158. data/ext/isomorfeus_ferret_ext/stem_UTF_8_swedish.c +294 -0
  159. data/ext/isomorfeus_ferret_ext/stem_UTF_8_swedish.h +6 -0
  160. data/ext/isomorfeus_ferret_ext/stem_UTF_8_turkish.c +2191 -0
  161. data/ext/isomorfeus_ferret_ext/stem_UTF_8_turkish.h +6 -0
  162. data/ext/isomorfeus_ferret_ext/stem_api.c +66 -0
  163. data/ext/isomorfeus_ferret_ext/stem_api.h +26 -0
  164. data/ext/isomorfeus_ferret_ext/stem_header.h +57 -0
  165. data/ext/isomorfeus_ferret_ext/stem_modules.h +190 -0
  166. data/ext/isomorfeus_ferret_ext/stem_modules.txt +50 -0
  167. data/ext/isomorfeus_ferret_ext/stem_utilities.c +478 -0
  168. data/ext/isomorfeus_ferret_ext/test.c +850 -0
  169. data/ext/isomorfeus_ferret_ext/test.h +416 -0
  170. data/ext/isomorfeus_ferret_ext/test_1710.c +63 -0
  171. data/ext/isomorfeus_ferret_ext/test_analysis.c +1221 -0
  172. data/ext/isomorfeus_ferret_ext/test_array.c +272 -0
  173. data/ext/isomorfeus_ferret_ext/test_bitvector.c +600 -0
  174. data/ext/isomorfeus_ferret_ext/test_compound_io.c +170 -0
  175. data/ext/isomorfeus_ferret_ext/test_document.c +156 -0
  176. data/ext/isomorfeus_ferret_ext/test_except.c +244 -0
  177. data/ext/isomorfeus_ferret_ext/test_fields.c +522 -0
  178. data/ext/isomorfeus_ferret_ext/test_file_deleter.c +185 -0
  179. data/ext/isomorfeus_ferret_ext/test_filter.c +331 -0
  180. data/ext/isomorfeus_ferret_ext/test_fs_store.c +25 -0
  181. data/ext/isomorfeus_ferret_ext/test_global.c +299 -0
  182. data/ext/isomorfeus_ferret_ext/test_hash.c +485 -0
  183. data/ext/isomorfeus_ferret_ext/test_hashset.c +288 -0
  184. data/ext/isomorfeus_ferret_ext/test_helper.c +47 -0
  185. data/ext/isomorfeus_ferret_ext/test_highlighter.c +548 -0
  186. data/ext/isomorfeus_ferret_ext/test_index.c +2323 -0
  187. data/ext/isomorfeus_ferret_ext/test_lang.c +74 -0
  188. data/ext/isomorfeus_ferret_ext/test_mempool.c +102 -0
  189. data/ext/isomorfeus_ferret_ext/test_multimapper.c +64 -0
  190. data/ext/isomorfeus_ferret_ext/test_priorityqueue.c +213 -0
  191. data/ext/isomorfeus_ferret_ext/test_q_const_score.c +84 -0
  192. data/ext/isomorfeus_ferret_ext/test_q_filtered.c +61 -0
  193. data/ext/isomorfeus_ferret_ext/test_q_fuzzy.c +241 -0
  194. data/ext/isomorfeus_ferret_ext/test_q_parser.c +464 -0
  195. data/ext/isomorfeus_ferret_ext/test_q_span.c +575 -0
  196. data/ext/isomorfeus_ferret_ext/test_ram_store.c +77 -0
  197. data/ext/isomorfeus_ferret_ext/test_search.c +1874 -0
  198. data/ext/isomorfeus_ferret_ext/test_segments.c +167 -0
  199. data/ext/isomorfeus_ferret_ext/test_similarity.c +25 -0
  200. data/ext/isomorfeus_ferret_ext/test_sort.c +333 -0
  201. data/ext/isomorfeus_ferret_ext/test_store.c +591 -0
  202. data/ext/isomorfeus_ferret_ext/test_store.h +3 -0
  203. data/ext/isomorfeus_ferret_ext/test_term.c +351 -0
  204. data/ext/isomorfeus_ferret_ext/test_term_vectors.c +373 -0
  205. data/ext/isomorfeus_ferret_ext/test_test.c +83 -0
  206. data/ext/isomorfeus_ferret_ext/test_threading.c +188 -0
  207. data/ext/isomorfeus_ferret_ext/testhelper.c +561 -0
  208. data/ext/isomorfeus_ferret_ext/testhelper.h +25 -0
  209. data/ext/isomorfeus_ferret_ext/tests_all.h +87 -0
  210. data/ext/isomorfeus_ferret_ext/uchar-ucs4.rl +1854 -0
  211. data/ext/isomorfeus_ferret_ext/uchar-utf8.rl +1999 -0
  212. data/ext/isomorfeus_ferret_ext/url.rl +27 -0
  213. data/ext/isomorfeus_ferret_ext/word_list.h +15156 -0
  214. data/lib/isomorfeus/ferret/document.rb +132 -0
  215. data/lib/isomorfeus/ferret/field_symbol.rb +85 -0
  216. data/lib/isomorfeus/ferret/index/field_infos.rb +48 -0
  217. data/lib/isomorfeus/ferret/index/index.rb +970 -0
  218. data/lib/isomorfeus/ferret/monitor.rb +323 -0
  219. data/lib/isomorfeus/ferret/stdlib_patches.rb +151 -0
  220. data/lib/isomorfeus/ferret/version.rb +5 -0
  221. data/lib/isomorfeus-ferret.rb +8 -0
  222. metadata +307 -0
@@ -0,0 +1,3084 @@
1
+ /* A Bison parser, made by GNU Bison 2.3. */
2
+
3
+ /* Skeleton implementation for Bison's Yacc-like parsers in C
4
+
5
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
6
+ Free Software Foundation, Inc.
7
+
8
+ This program is free software; you can redistribute it and/or modify
9
+ it under the terms of the GNU General Public License as published by
10
+ the Free Software Foundation; either version 2, or (at your option)
11
+ any later version.
12
+
13
+ This program is distributed in the hope that it will be useful,
14
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ GNU General Public License for more details.
17
+
18
+ You should have received a copy of the GNU General Public License
19
+ along with this program; if not, write to the Free Software
20
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
21
+ Boston, MA 02110-1301, USA. */
22
+
23
+ /* As a special exception, you may create a larger work that contains
24
+ part or all of the Bison parser skeleton and distribute that work
25
+ under terms of your choice, so long as that work isn't itself a
26
+ parser generator using the skeleton or a modified version thereof
27
+ as a parser skeleton. Alternatively, if you modify or redistribute
28
+ the parser skeleton itself, you may (at your option) remove this
29
+ special exception, which will cause the skeleton and the resulting
30
+ Bison output files to be licensed under the GNU General Public
31
+ License without this special exception.
32
+
33
+ This special exception was added by the Free Software Foundation in
34
+ version 2.2 of Bison. */
35
+
36
+ /* C LALR(1) parser skeleton written by Richard Stallman, by
37
+ simplifying the original so-called "semantic" parser. */
38
+
39
+ /* All symbols defined below should begin with yy or YY, to avoid
40
+ infringing on user name space. This should be done even for local
41
+ variables, as they might otherwise be expanded by user macros.
42
+ There are some unavoidable exceptions within include files to
43
+ define necessary library symbols; they are noted "INFRINGES ON
44
+ USER NAME SPACE" below. */
45
+
46
+ /* Identify Bison output. */
47
+ #define YYBISON 1
48
+
49
+ /* Bison version. */
50
+ #define YYBISON_VERSION "2.3"
51
+
52
+ /* Skeleton name. */
53
+ #define YYSKELETON_NAME "yacc.c"
54
+
55
+ /* Pure parsers. */
56
+ #define YYPURE 1
57
+
58
+ /* Using locations. */
59
+ #define YYLSP_NEEDED 0
60
+
61
+ /* Tokens. */
62
+ #ifndef YYTOKENTYPE
63
+ # define YYTOKENTYPE
64
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
65
+ know about them. */
66
+ enum yytokentype {
67
+ QWRD = 258,
68
+ WILD_STR = 259,
69
+ LOW = 260,
70
+ OR = 261,
71
+ AND = 262,
72
+ NOT = 263,
73
+ REQ = 264,
74
+ HIGH = 265
75
+ };
76
+ #endif
77
+ /* Tokens. */
78
+ #define QWRD 258
79
+ #define WILD_STR 259
80
+ #define LOW 260
81
+ #define OR 261
82
+ #define AND 262
83
+ #define NOT 263
84
+ #define REQ 264
85
+ #define HIGH 265
86
+
87
+ /* Copy the first part of user declarations. */
88
+ #line 84 "src/q_parser.y"
89
+
90
+ #include <string.h>
91
+ #include <ctype.h>
92
+ #include <wctype.h>
93
+ #include <assert.h>
94
+ #include "frt_global.h"
95
+ #include "frt_except.h"
96
+ #include "frt_search.h"
97
+ #include "frt_array.h"
98
+
99
+ typedef struct Phrase {
100
+ int size;
101
+ int capa;
102
+ int pos_inc;
103
+ FrtPhrasePosition *positions;
104
+ } Phrase;
105
+
106
+ #define BCA_INIT_CAPA 4
107
+ typedef struct BCArray {
108
+ int size;
109
+ int capa;
110
+ FrtBooleanClause **clauses;
111
+ } BCArray;
112
+
113
+ float frt_qp_default_fuzzy_min_sim = 0.5;
114
+ int frt_qp_default_fuzzy_pre_len = 0;
115
+
116
+
117
+
118
+ /* Enabling traces. */
119
+ #ifndef YYDEBUG
120
+ # define YYDEBUG 0
121
+ #endif
122
+
123
+ /* Enabling verbose error messages. */
124
+ #ifdef YYERROR_VERBOSE
125
+ # undef YYERROR_VERBOSE
126
+ # define YYERROR_VERBOSE 1
127
+ #else
128
+ # define YYERROR_VERBOSE 0
129
+ #endif
130
+
131
+ /* Enabling the token table. */
132
+ #ifndef YYTOKEN_TABLE
133
+ # define YYTOKEN_TABLE 0
134
+ #endif
135
+
136
+ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
137
+ typedef union YYSTYPE
138
+ #line 113 "src/q_parser.y"
139
+ {
140
+ FrtQuery *query;
141
+ FrtBooleanClause *bcls;
142
+ BCArray *bclss;
143
+ FrtHashSet *hashset;
144
+ Phrase *phrase;
145
+ char *str;
146
+ }
147
+ /* Line 187 of yacc.c. */
148
+ #line 163 "src/q_parser.c"
149
+ YYSTYPE;
150
+ # define yystype YYSTYPE /* obsolescent; will be withdrawn */
151
+ # define YYSTYPE_IS_DECLARED 1
152
+ # define YYSTYPE_IS_TRIVIAL 1
153
+ #endif
154
+
155
+
156
+
157
+ /* Copy the second part of user declarations. */
158
+ #line 121 "src/q_parser.y"
159
+
160
+ static int yylex(YYSTYPE *lvalp, FrtQParser *qp);
161
+ static int yyerror(FrtQParser *qp, char const *msg);
162
+
163
+ #define PHRASE_INIT_CAPA 4
164
+ static FrtQuery *get_bool_q(BCArray *bca);
165
+
166
+ static BCArray *first_cls(FrtBooleanClause *boolean_clause);
167
+ static BCArray *add_and_cls(BCArray *bca, FrtBooleanClause *clause);
168
+ static BCArray *add_or_cls(BCArray *bca, FrtBooleanClause *clause);
169
+ static BCArray *add_default_cls(FrtQParser *qp, BCArray *bca,
170
+ FrtBooleanClause *clause);
171
+ static void bca_destroy(BCArray *bca);
172
+
173
+ static FrtBooleanClause *get_bool_cls(FrtQuery *q, FrtBCType occur);
174
+
175
+ static FrtQuery *get_term_q(FrtQParser *qp, FrtSymbol field, char *word);
176
+ static FrtQuery *get_fuzzy_q(FrtQParser *qp, FrtSymbol field, char *word,
177
+ char *slop);
178
+ static FrtQuery *get_wild_q(FrtQParser *qp, FrtSymbol field, char *pattern);
179
+
180
+ static FrtHashSet *first_field(FrtQParser *qp, const char *field_name);
181
+ static FrtHashSet *add_field(FrtQParser *qp, const char *field_name);
182
+
183
+ static FrtQuery *get_phrase_q(FrtQParser *qp, Phrase *phrase, char *slop);
184
+
185
+ static Phrase *ph_first_word(char *word);
186
+ static Phrase *ph_add_word(Phrase *self, char *word);
187
+ static Phrase *ph_add_multi_word(Phrase *self, char *word);
188
+ static void ph_destroy(Phrase *self);
189
+
190
+ static FrtQuery *get_r_q(FrtQParser *qp, FrtSymbol field, char *from, char *to,
191
+ bool inc_lower, bool inc_upper);
192
+
193
+ static void qp_push_fields(FrtQParser *self, FrtHashSet *fields, bool destroy);
194
+ static void qp_pop_fields(FrtQParser *self);
195
+
196
+ /**
197
+ * +FLDS+ calls +func+ for all fields on top of the field stack. +func+
198
+ * must return a query. If there is more than one field on top of FieldStack
199
+ * then +FLDS+ will combing all the queries returned by +func+ into a single
200
+ * BooleanQuery which it than assigns to +q+. If there is only one field, the
201
+ * return value of +func+ is assigned to +q+ directly.
202
+ */
203
+ #define FLDS(q, func) do {\
204
+ FRT_TRY {\
205
+ FrtSymbol field;\
206
+ if (qp->fields->size == 0) {\
207
+ q = NULL;\
208
+ } else if (qp->fields->size == 1) {\
209
+ field = (FrtSymbol)qp->fields->first->elem;\
210
+ q = func;\
211
+ } else {\
212
+ FrtQuery *volatile sq; FrtHashSetEntry *volatile hse;\
213
+ q = frt_bq_new_max(false, qp->max_clauses);\
214
+ for (hse = qp->fields->first; hse; hse = hse->next) {\
215
+ field = (FrtSymbol)hse->elem;\
216
+ sq = func;\
217
+ FRT_TRY\
218
+ if (sq) frt_bq_add_query_nr(q, sq, FRT_BC_SHOULD);\
219
+ FRT_XCATCHALL\
220
+ if (sq) frt_q_deref(sq);\
221
+ FRT_XENDTRY\
222
+ }\
223
+ if (((FrtBooleanQuery *)q)->clause_cnt == 0) {\
224
+ frt_q_deref(q);\
225
+ q = NULL;\
226
+ }\
227
+ }\
228
+ } FRT_XCATCHALL\
229
+ qp->destruct = true;\
230
+ FRT_HANDLED();\
231
+ FRT_XENDTRY\
232
+ if (qp->destruct && !qp->recovering && q) {frt_q_deref(q); q = NULL;}\
233
+ } while (0)
234
+
235
+ #define Y if (qp->destruct) goto yyerrorlab;
236
+ #define T FRT_TRY
237
+ #define E\
238
+ FRT_XCATCHALL\
239
+ qp->destruct = true;\
240
+ FRT_HANDLED();\
241
+ FRT_XENDTRY\
242
+ if (qp->destruct) Y;
243
+
244
+
245
+ /* Line 216 of yacc.c. */
246
+ #line 261 "src/q_parser.c"
247
+
248
+ #ifdef short
249
+ # undef short
250
+ #endif
251
+
252
+ #ifdef YYTYPE_UINT8
253
+ typedef YYTYPE_UINT8 yytype_uint8;
254
+ #else
255
+ typedef unsigned char yytype_uint8;
256
+ #endif
257
+
258
+ #ifdef YYTYPE_INT8
259
+ typedef YYTYPE_INT8 yytype_int8;
260
+ #elif (defined __STDC__ || defined __C99__FUNC__ \
261
+ || defined __cplusplus || defined _MSC_VER)
262
+ typedef signed char yytype_int8;
263
+ #else
264
+ typedef short int yytype_int8;
265
+ #endif
266
+
267
+ #ifdef YYTYPE_UINT16
268
+ typedef YYTYPE_UINT16 yytype_uint16;
269
+ #else
270
+ typedef unsigned short int yytype_uint16;
271
+ #endif
272
+
273
+ #ifdef YYTYPE_INT16
274
+ typedef YYTYPE_INT16 yytype_int16;
275
+ #else
276
+ typedef short int yytype_int16;
277
+ #endif
278
+
279
+ #ifndef YYSIZE_T
280
+ # ifdef __SIZE_TYPE__
281
+ # define YYSIZE_T __SIZE_TYPE__
282
+ # elif defined size_t
283
+ # define YYSIZE_T size_t
284
+ # elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
285
+ || defined __cplusplus || defined _MSC_VER)
286
+ # include <stddef.h> /* INFRINGES ON USER NAME SPACE */
287
+ # define YYSIZE_T size_t
288
+ # else
289
+ # define YYSIZE_T unsigned int
290
+ # endif
291
+ #endif
292
+
293
+ #define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
294
+
295
+ #ifndef YY_
296
+ # if YYENABLE_NLS
297
+ # if ENABLE_NLS
298
+ # include <libintl.h> /* INFRINGES ON USER NAME SPACE */
299
+ # define YY_(msgid) dgettext ("bison-runtime", msgid)
300
+ # endif
301
+ # endif
302
+ # ifndef YY_
303
+ # define YY_(msgid) msgid
304
+ # endif
305
+ #endif
306
+
307
+ /* Suppress unused-variable warnings by "using" E. */
308
+ #if ! defined lint || defined __GNUC__
309
+ # define YYUSE(e) ((void) (e))
310
+ #else
311
+ # define YYUSE(e) /* empty */
312
+ #endif
313
+
314
+ /* Identity function, used to suppress warnings about constant conditions. */
315
+ #ifndef lint
316
+ # define YYID(n) (n)
317
+ #else
318
+ #if (defined __STDC__ || defined __C99__FUNC__ \
319
+ || defined __cplusplus || defined _MSC_VER)
320
+ static int
321
+ YYID (int i)
322
+ #else
323
+ static int
324
+ YYID (i)
325
+ int i;
326
+ #endif
327
+ {
328
+ return i;
329
+ }
330
+ #endif
331
+
332
+ #if ! defined yyoverflow || YYERROR_VERBOSE
333
+
334
+ /* The parser invokes alloca or malloc; define the necessary symbols. */
335
+
336
+ # ifdef YYSTACK_USE_ALLOCA
337
+ # if YYSTACK_USE_ALLOCA
338
+ # ifdef __GNUC__
339
+ # define YYSTACK_ALLOC __builtin_alloca
340
+ # elif defined __BUILTIN_VA_ARG_INCR
341
+ # include <alloca.h> /* INFRINGES ON USER NAME SPACE */
342
+ # elif defined _AIX
343
+ # define YYSTACK_ALLOC __alloca
344
+ # elif defined _MSC_VER
345
+ # include <malloc.h> /* INFRINGES ON USER NAME SPACE */
346
+ # define alloca _alloca
347
+ # else
348
+ # define YYSTACK_ALLOC alloca
349
+ # if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
350
+ || defined __cplusplus || defined _MSC_VER)
351
+ # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
352
+ # ifndef _STDLIB_H
353
+ # define _STDLIB_H 1
354
+ # endif
355
+ # endif
356
+ # endif
357
+ # endif
358
+ # endif
359
+
360
+ # ifdef YYSTACK_ALLOC
361
+ /* Pacify GCC's `empty if-body' warning. */
362
+ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
363
+ # ifndef YYSTACK_ALLOC_MAXIMUM
364
+ /* The OS might guarantee only one guard page at the bottom of the stack,
365
+ and a page size can be as small as 4096 bytes. So we cannot safely
366
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
367
+ to allow for a few compiler-allocated temporary stack slots. */
368
+ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
369
+ # endif
370
+ # else
371
+ # define YYSTACK_ALLOC YYMALLOC
372
+ # define YYSTACK_FREE YYFREE
373
+ # ifndef YYSTACK_ALLOC_MAXIMUM
374
+ # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
375
+ # endif
376
+ # if (defined __cplusplus && ! defined _STDLIB_H \
377
+ && ! ((defined YYMALLOC || defined malloc) \
378
+ && (defined YYFREE || defined free)))
379
+ # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
380
+ # ifndef _STDLIB_H
381
+ # define _STDLIB_H 1
382
+ # endif
383
+ # endif
384
+ # ifndef YYMALLOC
385
+ # define YYMALLOC malloc
386
+ # if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
387
+ || defined __cplusplus || defined _MSC_VER)
388
+ void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
389
+ # endif
390
+ # endif
391
+ # ifndef YYFREE
392
+ # define YYFREE free
393
+ # if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
394
+ || defined __cplusplus || defined _MSC_VER)
395
+ void free (void *); /* INFRINGES ON USER NAME SPACE */
396
+ # endif
397
+ # endif
398
+ # endif
399
+ #endif /* ! defined yyoverflow || YYERROR_VERBOSE */
400
+
401
+
402
+ #if (! defined yyoverflow \
403
+ && (! defined __cplusplus \
404
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
405
+
406
+ /* A type that is properly aligned for any stack member. */
407
+ union yyalloc
408
+ {
409
+ yytype_int16 yyss;
410
+ YYSTYPE yyvs;
411
+ };
412
+
413
+ /* The size of the maximum gap between one aligned stack and the next. */
414
+ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
415
+
416
+ /* The size of an array large to enough to hold all stacks, each with
417
+ N elements. */
418
+ # define YYSTACK_BYTES(N) \
419
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
420
+ + YYSTACK_GAP_MAXIMUM)
421
+
422
+ /* Copy COUNT objects from FROM to TO. The source and destination do
423
+ not overlap. */
424
+ # ifndef YYCOPY
425
+ # if defined __GNUC__ && 1 < __GNUC__
426
+ # define YYCOPY(To, From, Count) \
427
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
428
+ # else
429
+ # define YYCOPY(To, From, Count) \
430
+ do \
431
+ { \
432
+ YYSIZE_T yyi; \
433
+ for (yyi = 0; yyi < (Count); yyi++) \
434
+ (To)[yyi] = (From)[yyi]; \
435
+ } \
436
+ while (YYID (0))
437
+ # endif
438
+ # endif
439
+
440
+ /* Relocate STACK from its old location to the new one. The
441
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
442
+ elements in the stack, and YYPTR gives the new location of the
443
+ stack. Advance YYPTR to a properly aligned location for the next
444
+ stack. */
445
+ # define YYSTACK_RELOCATE(Stack) \
446
+ do \
447
+ { \
448
+ YYSIZE_T yynewbytes; \
449
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
450
+ Stack = &yyptr->Stack; \
451
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
452
+ yyptr += yynewbytes / sizeof (*yyptr); \
453
+ } \
454
+ while (YYID (0))
455
+
456
+ #endif
457
+
458
+ /* YYFINAL -- State number of the termination state. */
459
+ #define YYFINAL 39
460
+ /* YYLAST -- Last index in YYTABLE. */
461
+ #define YYLAST 126
462
+
463
+ /* YYNTOKENS -- Number of terminals. */
464
+ #define YYNTOKENS 26
465
+ /* YYNNTS -- Number of nonterminals. */
466
+ #define YYNNTS 16
467
+ /* YYNRULES -- Number of rules. */
468
+ #define YYNRULES 51
469
+ /* YYNRULES -- Number of states. */
470
+ #define YYNSTATES 80
471
+
472
+ /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
473
+ #define YYUNDEFTOK 2
474
+ #define YYMAXUTOK 265
475
+
476
+ #define YYTRANSLATE(YYX) \
477
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
478
+
479
+ /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
480
+ static const yytype_uint8 yytranslate[] =
481
+ {
482
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
483
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
484
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
485
+ 2, 2, 2, 2, 18, 2, 2, 2, 2, 2,
486
+ 13, 14, 16, 2, 2, 2, 2, 2, 2, 2,
487
+ 2, 2, 2, 2, 2, 2, 2, 2, 10, 2,
488
+ 19, 25, 20, 2, 2, 2, 2, 2, 2, 2,
489
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
490
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
491
+ 2, 21, 2, 22, 12, 2, 2, 2, 2, 2,
492
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
493
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
494
+ 2, 2, 2, 24, 17, 23, 15, 2, 2, 2,
495
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
496
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
497
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
498
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
499
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
500
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
501
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
502
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
503
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
504
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
505
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
506
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
507
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
508
+ 5, 6, 7, 8, 9, 11
509
+ };
510
+
511
+ #if YYDEBUG
512
+ /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
513
+ YYRHS. */
514
+ static const yytype_uint8 yyprhs[] =
515
+ {
516
+ 0, 0, 3, 4, 6, 8, 12, 16, 19, 22,
517
+ 25, 27, 29, 33, 35, 38, 42, 44, 46, 48,
518
+ 50, 52, 56, 59, 61, 62, 67, 68, 69, 75,
519
+ 77, 81, 85, 91, 94, 99, 101, 104, 107, 111,
520
+ 115, 120, 125, 130, 135, 139, 143, 147, 151, 154,
521
+ 158, 162
522
+ };
523
+
524
+ /* YYRHS -- A `-1'-separated list of the rules' RHS. */
525
+ static const yytype_int8 yyrhs[] =
526
+ {
527
+ 27, 0, -1, -1, 28, -1, 29, -1, 28, 7,
528
+ 29, -1, 28, 6, 29, -1, 28, 29, -1, 9,
529
+ 30, -1, 8, 30, -1, 30, -1, 31, -1, 31,
530
+ 12, 3, -1, 32, -1, 13, 14, -1, 13, 28,
531
+ 14, -1, 34, -1, 39, -1, 41, -1, 33, -1,
532
+ 3, -1, 3, 15, 3, -1, 3, 15, -1, 4,
533
+ -1, -1, 38, 10, 31, 35, -1, -1, -1, 16,
534
+ 36, 10, 31, 37, -1, 3, -1, 38, 17, 3,
535
+ -1, 18, 40, 18, -1, 18, 40, 18, 15, 3,
536
+ -1, 18, 18, -1, 18, 18, 15, 3, -1, 3,
537
+ -1, 19, 20, -1, 40, 3, -1, 40, 19, 20,
538
+ -1, 40, 17, 3, -1, 21, 3, 3, 22, -1,
539
+ 21, 3, 3, 23, -1, 24, 3, 3, 22, -1,
540
+ 24, 3, 3, 23, -1, 19, 3, 23, -1, 19,
541
+ 3, 22, -1, 21, 3, 20, -1, 24, 3, 20,
542
+ -1, 19, 3, -1, 19, 25, 3, -1, 20, 25,
543
+ 3, -1, 20, 3, -1
544
+ };
545
+
546
+ /* YYRLINE[YYN] -- source line where rule number YYN was defined. */
547
+ static const yytype_uint16 yyrline[] =
548
+ {
549
+ 0, 226, 226, 227, 229, 230, 231, 232, 234, 235,
550
+ 236, 238, 239, 241, 242, 243, 244, 245, 246, 247,
551
+ 249, 250, 251, 253, 255, 255, 257, 257, 257, 260,
552
+ 261, 263, 264, 265, 266, 268, 269, 270, 271, 272,
553
+ 274, 275, 276, 277, 278, 279, 280, 281, 282, 283,
554
+ 284, 285
555
+ };
556
+ #endif
557
+
558
+ #if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
559
+ /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
560
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
561
+ static const char *const yytname[] =
562
+ {
563
+ "$end", "error", "$undefined", "QWRD", "WILD_STR", "LOW", "OR", "AND",
564
+ "NOT", "REQ", "':'", "HIGH", "'^'", "'('", "')'", "'~'", "'*'", "'|'",
565
+ "'\"'", "'<'", "'>'", "'['", "']'", "'}'", "'{'", "'='", "$accept",
566
+ "bool_q", "bool_clss", "bool_cls", "boosted_q", "q", "term_q", "wild_q",
567
+ "field_q", "@1", "@2", "@3", "field", "phrase_q", "ph_words", "range_q", 0
568
+ };
569
+ #endif
570
+
571
+ # ifdef YYPRINT
572
+ /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
573
+ token YYLEX-NUM. */
574
+ static const yytype_uint16 yytoknum[] =
575
+ {
576
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
577
+ 58, 265, 94, 40, 41, 126, 42, 124, 34, 60,
578
+ 62, 91, 93, 125, 123, 61
579
+ };
580
+ # endif
581
+
582
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
583
+ static const yytype_uint8 yyr1[] =
584
+ {
585
+ 0, 26, 27, 27, 28, 28, 28, 28, 29, 29,
586
+ 29, 30, 30, 31, 31, 31, 31, 31, 31, 31,
587
+ 32, 32, 32, 33, 35, 34, 36, 37, 34, 38,
588
+ 38, 39, 39, 39, 39, 40, 40, 40, 40, 40,
589
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
590
+ 41, 41
591
+ };
592
+
593
+ /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
594
+ static const yytype_uint8 yyr2[] =
595
+ {
596
+ 0, 2, 0, 1, 1, 3, 3, 2, 2, 2,
597
+ 1, 1, 3, 1, 2, 3, 1, 1, 1, 1,
598
+ 1, 3, 2, 1, 0, 4, 0, 0, 5, 1,
599
+ 3, 3, 5, 2, 4, 1, 2, 2, 3, 3,
600
+ 4, 4, 4, 4, 3, 3, 3, 3, 2, 3,
601
+ 3, 2
602
+ };
603
+
604
+ /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
605
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
606
+ means the default is an error. */
607
+ static const yytype_uint8 yydefact[] =
608
+ {
609
+ 2, 20, 23, 0, 0, 0, 26, 0, 0, 0,
610
+ 0, 0, 0, 3, 4, 10, 11, 13, 19, 16,
611
+ 0, 17, 18, 22, 9, 8, 14, 0, 0, 35,
612
+ 33, 0, 0, 48, 0, 51, 0, 0, 0, 1,
613
+ 0, 0, 7, 0, 0, 0, 21, 15, 0, 0,
614
+ 36, 37, 0, 31, 0, 45, 44, 49, 50, 0,
615
+ 46, 0, 47, 6, 5, 12, 24, 30, 27, 34,
616
+ 39, 0, 38, 40, 41, 42, 43, 25, 28, 32
617
+ };
618
+
619
+ /* YYDEFGOTO[NTERM-NUM]. */
620
+ static const yytype_int8 yydefgoto[] =
621
+ {
622
+ -1, 12, 13, 14, 15, 16, 17, 18, 19, 77,
623
+ 28, 78, 20, 21, 32, 22
624
+ };
625
+
626
+ /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
627
+ STATE-NUM. */
628
+ #define YYPACT_NINF -30
629
+ static const yytype_int8 yypact[] =
630
+ {
631
+ 83, -4, -30, 102, 102, 64, -30, 7, -2, -1,
632
+ 6, 15, 31, 45, -30, -30, 29, -30, -30, -30,
633
+ -5, -30, -30, 40, -30, -30, -30, 26, 47, -30,
634
+ 55, 42, 19, -15, 68, -30, 71, 0, 1, -30,
635
+ 83, 83, -30, 72, 102, 73, -30, -30, 102, 76,
636
+ -30, -30, 78, 74, 70, -30, -30, -30, -30, -6,
637
+ -30, 33, -30, -30, -30, -30, -30, -30, -30, -30,
638
+ -30, 90, -30, -30, -30, -30, -30, -30, -30, -30
639
+ };
640
+
641
+ /* YYPGOTO[NTERM-NUM]. */
642
+ static const yytype_int8 yypgoto[] =
643
+ {
644
+ -30, -30, 89, -13, 56, -29, -30, -30, -30, -30,
645
+ -30, -30, -30, -30, -30, -30
646
+ };
647
+
648
+ /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
649
+ positive, shift that token. If negative, reduce the rule which
650
+ number is the opposite. If zero, do what YYDEFACT says.
651
+ If YYTABLE_NINF, syntax error. */
652
+ #define YYTABLE_NINF -30
653
+ static const yytype_int8 yytable[] =
654
+ {
655
+ 42, 33, 35, 59, 61, 44, -29, 55, 56, 37,
656
+ 29, 23, 45, -29, 42, 66, 73, 74, 38, 68,
657
+ 60, 62, 51, 34, 36, 30, 31, 63, 64, 1,
658
+ 2, 39, 40, 41, 3, 4, 52, 53, 54, 5,
659
+ 47, 43, 6, 46, 7, 8, 9, 10, 1, 2,
660
+ 11, 40, 41, 3, 4, 75, 76, 48, 5, 24,
661
+ 25, 6, 50, 7, 8, 9, 10, 1, 2, 11,
662
+ 49, 57, 3, 4, 58, 65, 67, 5, 26, 69,
663
+ 6, 70, 7, 8, 9, 10, 1, 2, 11, 71,
664
+ 72, 3, 4, 79, 27, 0, 5, 0, 0, 6,
665
+ 0, 7, 8, 9, 10, 1, 2, 11, 0, 0,
666
+ 0, 0, 0, 0, 0, 5, 0, 0, 6, 0,
667
+ 7, 8, 9, 10, 0, 0, 11
668
+ };
669
+
670
+ static const yytype_int8 yycheck[] =
671
+ {
672
+ 13, 3, 3, 3, 3, 10, 10, 22, 23, 3,
673
+ 3, 15, 17, 17, 27, 44, 22, 23, 3, 48,
674
+ 20, 20, 3, 25, 25, 18, 19, 40, 41, 3,
675
+ 4, 0, 6, 7, 8, 9, 17, 18, 19, 13,
676
+ 14, 12, 16, 3, 18, 19, 20, 21, 3, 4,
677
+ 24, 6, 7, 8, 9, 22, 23, 10, 13, 3,
678
+ 4, 16, 20, 18, 19, 20, 21, 3, 4, 24,
679
+ 15, 3, 8, 9, 3, 3, 3, 13, 14, 3,
680
+ 16, 3, 18, 19, 20, 21, 3, 4, 24, 15,
681
+ 20, 8, 9, 3, 5, -1, 13, -1, -1, 16,
682
+ -1, 18, 19, 20, 21, 3, 4, 24, -1, -1,
683
+ -1, -1, -1, -1, -1, 13, -1, -1, 16, -1,
684
+ 18, 19, 20, 21, -1, -1, 24
685
+ };
686
+
687
+ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
688
+ symbol of state STATE-NUM. */
689
+ static const yytype_uint8 yystos[] =
690
+ {
691
+ 0, 3, 4, 8, 9, 13, 16, 18, 19, 20,
692
+ 21, 24, 27, 28, 29, 30, 31, 32, 33, 34,
693
+ 38, 39, 41, 15, 30, 30, 14, 28, 36, 3,
694
+ 18, 19, 40, 3, 25, 3, 25, 3, 3, 0,
695
+ 6, 7, 29, 12, 10, 17, 3, 14, 10, 15,
696
+ 20, 3, 17, 18, 19, 22, 23, 3, 3, 3,
697
+ 20, 3, 20, 29, 29, 3, 31, 3, 31, 3,
698
+ 3, 15, 20, 22, 23, 22, 23, 35, 37, 3
699
+ };
700
+
701
+ #define yyerrok (yyerrstatus = 0)
702
+ #define yyclearin (yychar = YYEMPTY)
703
+ #define YYEMPTY (-2)
704
+ #define YYEOF 0
705
+
706
+ #define YYACCEPT goto yyacceptlab
707
+ #define YYABORT goto yyabortlab
708
+ #define YYERROR goto yyerrorlab
709
+
710
+
711
+ /* Like YYERROR except do call yyerror. This remains here temporarily
712
+ to ease the transition to the new meaning of YYERROR, for GCC.
713
+ Once GCC version 2 has supplanted version 1, this can go. */
714
+
715
+ #define YYFAIL goto yyerrlab
716
+
717
+ #define YYRECOVERING() (!!yyerrstatus)
718
+
719
+ #define YYBACKUP(FrtToken, Value) \
720
+ do \
721
+ if (yychar == YYEMPTY && yylen == 1) \
722
+ { \
723
+ yychar = (FrtToken); \
724
+ yylval = (Value); \
725
+ yytoken = YYTRANSLATE (yychar); \
726
+ YYPOPSTACK (1); \
727
+ goto yybackup; \
728
+ } \
729
+ else \
730
+ { \
731
+ yyerror (qp, YY_("syntax error: cannot back up")); \
732
+ YYERROR; \
733
+ } \
734
+ while (YYID (0))
735
+
736
+
737
+ #define YYTERROR 1
738
+ #define YYERRCODE 256
739
+
740
+
741
+ /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
742
+ If N is 0, then set CURRENT to the empty location which ends
743
+ the previous symbol: RHS[0] (always defined). */
744
+
745
+ #define YYRHSLOC(Rhs, K) ((Rhs)[K])
746
+ #ifndef YYLLOC_DEFAULT
747
+ # define YYLLOC_DEFAULT(Current, Rhs, N) \
748
+ do \
749
+ if (YYID (N)) \
750
+ { \
751
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
752
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
753
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
754
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
755
+ } \
756
+ else \
757
+ { \
758
+ (Current).first_line = (Current).last_line = \
759
+ YYRHSLOC (Rhs, 0).last_line; \
760
+ (Current).first_column = (Current).last_column = \
761
+ YYRHSLOC (Rhs, 0).last_column; \
762
+ } \
763
+ while (YYID (0))
764
+ #endif
765
+
766
+
767
+ /* YY_LOCATION_PRINT -- Print the location on the stream.
768
+ This macro was not mandated originally: define only if we know
769
+ we won't break user code: when these are the locations we know. */
770
+
771
+ #ifndef YY_LOCATION_PRINT
772
+ # if YYLTYPE_IS_TRIVIAL
773
+ # define YY_LOCATION_PRINT(File, Loc) \
774
+ fprintf (File, "%d.%d-%d.%d", \
775
+ (Loc).first_line, (Loc).first_column, \
776
+ (Loc).last_line, (Loc).last_column)
777
+ # else
778
+ # define YY_LOCATION_PRINT(File, Loc) ((void) 0)
779
+ # endif
780
+ #endif
781
+
782
+
783
+ /* YYLEX -- calling `yylex' with the right arguments. */
784
+
785
+ #ifdef YYLEX_PARAM
786
+ # define YYLEX yylex (&yylval, YYLEX_PARAM)
787
+ #else
788
+ # define YYLEX yylex (&yylval, qp)
789
+ #endif
790
+
791
+ /* Enable debugging if requested. */
792
+ #if YYDEBUG
793
+
794
+ # ifndef YYFPRINTF
795
+ # include <stdio.h> /* INFRINGES ON USER NAME SPACE */
796
+ # define YYFPRINTF fprintf
797
+ # endif
798
+
799
+ # define YYDPRINTF(Args) \
800
+ do { \
801
+ if (yydebug) \
802
+ YYFPRINTF Args; \
803
+ } while (YYID (0))
804
+
805
+ # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
806
+ do { \
807
+ if (yydebug) \
808
+ { \
809
+ YYFPRINTF (stderr, "%s ", Title); \
810
+ yy_symbol_print (stderr, \
811
+ Type, Value, qp); \
812
+ YYFPRINTF (stderr, "\n"); \
813
+ } \
814
+ } while (YYID (0))
815
+
816
+
817
+ /*--------------------------------.
818
+ | Print this symbol on YYOUTPUT. |
819
+ `--------------------------------*/
820
+
821
+ /*ARGSUSED*/
822
+ #if (defined __STDC__ || defined __C99__FUNC__ \
823
+ || defined __cplusplus || defined _MSC_VER)
824
+ static void
825
+ yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, FrtQParser *qp)
826
+ #else
827
+ static void
828
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep, qp)
829
+ FILE *yyoutput;
830
+ int yytype;
831
+ YYSTYPE const * const yyvaluep;
832
+ FrtQParser *qp;
833
+ #endif
834
+ {
835
+ if (!yyvaluep)
836
+ return;
837
+ YYUSE (qp);
838
+ # ifdef YYPRINT
839
+ if (yytype < YYNTOKENS)
840
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
841
+ # else
842
+ YYUSE (yyoutput);
843
+ # endif
844
+ switch (yytype)
845
+ {
846
+ default:
847
+ break;
848
+ }
849
+ }
850
+
851
+
852
+ /*--------------------------------.
853
+ | Print this symbol on YYOUTPUT. |
854
+ `--------------------------------*/
855
+
856
+ #if (defined __STDC__ || defined __C99__FUNC__ \
857
+ || defined __cplusplus || defined _MSC_VER)
858
+ static void
859
+ yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, FrtQParser *qp)
860
+ #else
861
+ static void
862
+ yy_symbol_print (yyoutput, yytype, yyvaluep, qp)
863
+ FILE *yyoutput;
864
+ int yytype;
865
+ YYSTYPE const * const yyvaluep;
866
+ FrtQParser *qp;
867
+ #endif
868
+ {
869
+ if (yytype < YYNTOKENS)
870
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
871
+ else
872
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
873
+
874
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep, qp);
875
+ YYFPRINTF (yyoutput, ")");
876
+ }
877
+
878
+ /*------------------------------------------------------------------.
879
+ | yy_stack_print -- Print the state stack from its BOTTOM up to its |
880
+ | TOP (included). |
881
+ `------------------------------------------------------------------*/
882
+
883
+ #if (defined __STDC__ || defined __C99__FUNC__ \
884
+ || defined __cplusplus || defined _MSC_VER)
885
+ static void
886
+ yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
887
+ #else
888
+ static void
889
+ yy_stack_print (bottom, top)
890
+ yytype_int16 *bottom;
891
+ yytype_int16 *top;
892
+ #endif
893
+ {
894
+ YYFPRINTF (stderr, "Stack now");
895
+ for (; bottom <= top; ++bottom)
896
+ YYFPRINTF (stderr, " %d", *bottom);
897
+ YYFPRINTF (stderr, "\n");
898
+ }
899
+
900
+ # define YY_STACK_PRINT(Bottom, Top) \
901
+ do { \
902
+ if (yydebug) \
903
+ yy_stack_print ((Bottom), (Top)); \
904
+ } while (YYID (0))
905
+
906
+
907
+ /*------------------------------------------------.
908
+ | Report that the YYRULE is going to be reduced. |
909
+ `------------------------------------------------*/
910
+
911
+ #if (defined __STDC__ || defined __C99__FUNC__ \
912
+ || defined __cplusplus || defined _MSC_VER)
913
+ static void
914
+ yy_reduce_print (YYSTYPE *yyvsp, int yyrule, FrtQParser *qp)
915
+ #else
916
+ static void
917
+ yy_reduce_print (yyvsp, yyrule, qp)
918
+ YYSTYPE *yyvsp;
919
+ int yyrule;
920
+ FrtQParser *qp;
921
+ #endif
922
+ {
923
+ int yynrhs = yyr2[yyrule];
924
+ int yyi;
925
+ unsigned long int yylno = yyrline[yyrule];
926
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
927
+ yyrule - 1, yylno);
928
+ /* The symbols being reduced. */
929
+ for (yyi = 0; yyi < yynrhs; yyi++)
930
+ {
931
+ fprintf (stderr, " $%d = ", yyi + 1);
932
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
933
+ &(yyvsp[(yyi + 1) - (yynrhs)])
934
+ , qp);
935
+ fprintf (stderr, "\n");
936
+ }
937
+ }
938
+
939
+ # define YY_REDUCE_PRINT(Rule) \
940
+ do { \
941
+ if (yydebug) \
942
+ yy_reduce_print (yyvsp, Rule, qp); \
943
+ } while (YYID (0))
944
+
945
+ /* Nonzero means print parse trace. It is left uninitialized so that
946
+ multiple parsers can coexist. */
947
+ int yydebug;
948
+ #else /* !YYDEBUG */
949
+ # define YYDPRINTF(Args)
950
+ # define YY_SYMBOL_PRINT(Title, Type, Value, Location)
951
+ # define YY_STACK_PRINT(Bottom, Top)
952
+ # define YY_REDUCE_PRINT(Rule)
953
+ #endif /* !YYDEBUG */
954
+
955
+
956
+ /* YYINITDEPTH -- initial size of the parser's stacks. */
957
+ #ifndef YYINITDEPTH
958
+ # define YYINITDEPTH 200
959
+ #endif
960
+
961
+ /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
962
+ if the built-in stack extension method is used).
963
+
964
+ Do not make this value too large; the results are undefined if
965
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
966
+ evaluated with infinite-precision integer arithmetic. */
967
+
968
+ #ifndef YYMAXDEPTH
969
+ # define YYMAXDEPTH 10000
970
+ #endif
971
+
972
+
973
+
974
+ #if YYERROR_VERBOSE
975
+
976
+ # ifndef yystrlen
977
+ # if defined __GLIBC__ && defined _STRING_H
978
+ # define yystrlen strlen
979
+ # else
980
+ /* Return the length of YYSTR. */
981
+ #if (defined __STDC__ || defined __C99__FUNC__ \
982
+ || defined __cplusplus || defined _MSC_VER)
983
+ static YYSIZE_T
984
+ yystrlen (const char *yystr)
985
+ #else
986
+ static YYSIZE_T
987
+ yystrlen (yystr)
988
+ const char *yystr;
989
+ #endif
990
+ {
991
+ YYSIZE_T yylen;
992
+ for (yylen = 0; yystr[yylen]; yylen++)
993
+ continue;
994
+ return yylen;
995
+ }
996
+ # endif
997
+ # endif
998
+
999
+ # ifndef yystpcpy
1000
+ # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
1001
+ # define yystpcpy stpcpy
1002
+ # else
1003
+ /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
1004
+ YYDEST. */
1005
+ #if (defined __STDC__ || defined __C99__FUNC__ \
1006
+ || defined __cplusplus || defined _MSC_VER)
1007
+ static char *
1008
+ yystpcpy (char *yydest, const char *yysrc)
1009
+ #else
1010
+ static char *
1011
+ yystpcpy (yydest, yysrc)
1012
+ char *yydest;
1013
+ const char *yysrc;
1014
+ #endif
1015
+ {
1016
+ char *yyd = yydest;
1017
+ const char *yys = yysrc;
1018
+
1019
+ while ((*yyd++ = *yys++) != '\0')
1020
+ continue;
1021
+
1022
+ return yyd - 1;
1023
+ }
1024
+ # endif
1025
+ # endif
1026
+
1027
+ # ifndef yytnamerr
1028
+ /* Copy to YYRES the contents of YYSTR after stripping away unnecessary
1029
+ quotes and backslashes, so that it's suitable for yyerror. The
1030
+ heuristic is that double-quoting is unnecessary unless the string
1031
+ contains an apostrophe, a comma, or backslash (other than
1032
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
1033
+ null, do not copy; instead, return the length of what the result
1034
+ would have been. */
1035
+ static YYSIZE_T
1036
+ yytnamerr (char *yyres, const char *yystr)
1037
+ {
1038
+ if (*yystr == '"')
1039
+ {
1040
+ YYSIZE_T yyn = 0;
1041
+ char const *yyp = yystr;
1042
+
1043
+ for (;;)
1044
+ switch (*++yyp)
1045
+ {
1046
+ case '\'':
1047
+ case ',':
1048
+ goto do_not_strip_quotes;
1049
+
1050
+ case '\\':
1051
+ if (*++yyp != '\\')
1052
+ goto do_not_strip_quotes;
1053
+ /* Fall through. */
1054
+ default:
1055
+ if (yyres)
1056
+ yyres[yyn] = *yyp;
1057
+ yyn++;
1058
+ break;
1059
+
1060
+ case '"':
1061
+ if (yyres)
1062
+ yyres[yyn] = '\0';
1063
+ return yyn;
1064
+ }
1065
+ do_not_strip_quotes: ;
1066
+ }
1067
+
1068
+ if (! yyres)
1069
+ return yystrlen (yystr);
1070
+
1071
+ return yystpcpy (yyres, yystr) - yyres;
1072
+ }
1073
+ # endif
1074
+
1075
+ /* Copy into YYRESULT an error message about the unexpected token
1076
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
1077
+ including the terminating null byte. If YYRESULT is null, do not
1078
+ copy anything; just return the number of bytes that would be
1079
+ copied. As a special case, return 0 if an ordinary "syntax error"
1080
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
1081
+ size calculation. */
1082
+ static YYSIZE_T
1083
+ yysyntax_error (char *yyresult, int yystate, int yychar)
1084
+ {
1085
+ int yyn = yypact[yystate];
1086
+
1087
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
1088
+ return 0;
1089
+ else
1090
+ {
1091
+ int yytype = YYTRANSLATE (yychar);
1092
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
1093
+ YYSIZE_T yysize = yysize0;
1094
+ YYSIZE_T yysize1;
1095
+ int yysize_overflow = 0;
1096
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
1097
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
1098
+ int yyx;
1099
+
1100
+ # if 0
1101
+ /* This is so xgettext sees the translatable formats that are
1102
+ constructed on the fly. */
1103
+ YY_("syntax error, unexpected %s");
1104
+ YY_("syntax error, unexpected %s, expecting %s");
1105
+ YY_("syntax error, unexpected %s, expecting %s or %s");
1106
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
1107
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
1108
+ # endif
1109
+ char *yyfmt;
1110
+ char const *yyf;
1111
+ static char const yyunexpected[] = "syntax error, unexpected %s";
1112
+ static char const yyexpecting[] = ", expecting %s";
1113
+ static char const yyor[] = " or %s";
1114
+ char yyformat[sizeof yyunexpected
1115
+ + sizeof yyexpecting - 1
1116
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
1117
+ * (sizeof yyor - 1))];
1118
+ char const *yyprefix = yyexpecting;
1119
+
1120
+ /* Start YYX at -YYN if negative to avoid negative indexes in
1121
+ YYCHECK. */
1122
+ int yyxbegin = yyn < 0 ? -yyn : 0;
1123
+
1124
+ /* Stay within bounds of both yycheck and yytname. */
1125
+ int yychecklim = YYLAST - yyn + 1;
1126
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
1127
+ int yycount = 1;
1128
+
1129
+ yyarg[0] = yytname[yytype];
1130
+ yyfmt = yystpcpy (yyformat, yyunexpected);
1131
+
1132
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
1133
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
1134
+ {
1135
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
1136
+ {
1137
+ yycount = 1;
1138
+ yysize = yysize0;
1139
+ yyformat[sizeof yyunexpected - 1] = '\0';
1140
+ break;
1141
+ }
1142
+ yyarg[yycount++] = yytname[yyx];
1143
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
1144
+ yysize_overflow |= (yysize1 < yysize);
1145
+ yysize = yysize1;
1146
+ yyfmt = yystpcpy (yyfmt, yyprefix);
1147
+ yyprefix = yyor;
1148
+ }
1149
+
1150
+ yyf = YY_(yyformat);
1151
+ yysize1 = yysize + yystrlen (yyf);
1152
+ yysize_overflow |= (yysize1 < yysize);
1153
+ yysize = yysize1;
1154
+
1155
+ if (yysize_overflow)
1156
+ return YYSIZE_MAXIMUM;
1157
+
1158
+ if (yyresult)
1159
+ {
1160
+ /* Avoid sprintf, as that infringes on the user's name space.
1161
+ Don't have undefined behavior even if the translation
1162
+ produced a string with the wrong number of "%s"s. */
1163
+ char *yyp = yyresult;
1164
+ int yyi = 0;
1165
+ while ((*yyp = *yyf) != '\0')
1166
+ {
1167
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
1168
+ {
1169
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
1170
+ yyf += 2;
1171
+ }
1172
+ else
1173
+ {
1174
+ yyp++;
1175
+ yyf++;
1176
+ }
1177
+ }
1178
+ }
1179
+ return yysize;
1180
+ }
1181
+ }
1182
+ #endif /* YYERROR_VERBOSE */
1183
+
1184
+
1185
+ /*-----------------------------------------------.
1186
+ | Release the memory associated to this symbol. |
1187
+ `-----------------------------------------------*/
1188
+
1189
+ /*ARGSUSED*/
1190
+ #if (defined __STDC__ || defined __C99__FUNC__ \
1191
+ || defined __cplusplus || defined _MSC_VER)
1192
+ static void
1193
+ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, FrtQParser *qp)
1194
+ #else
1195
+ static void
1196
+ yydestruct (yymsg, yytype, yyvaluep, qp)
1197
+ const char *yymsg;
1198
+ int yytype;
1199
+ YYSTYPE *yyvaluep;
1200
+ FrtQParser *qp;
1201
+ #endif
1202
+ {
1203
+ YYUSE (yyvaluep);
1204
+ YYUSE (qp);
1205
+
1206
+ if (!yymsg)
1207
+ yymsg = "Deleting";
1208
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
1209
+
1210
+ switch (yytype)
1211
+ {
1212
+ case 27: /* "bool_q" */
1213
+ #line 221 "src/q_parser.y"
1214
+ { if ((yyvaluep->query) && qp->destruct) frt_q_deref((yyvaluep->query)); };
1215
+ #line 1230 "src/q_parser.c"
1216
+ break;
1217
+ case 28: /* "bool_clss" */
1218
+ #line 223 "src/q_parser.y"
1219
+ { if ((yyvaluep->bclss) && qp->destruct) bca_destroy((yyvaluep->bclss)); };
1220
+ #line 1235 "src/q_parser.c"
1221
+ break;
1222
+ case 29: /* "bool_cls" */
1223
+ #line 222 "src/q_parser.y"
1224
+ { if ((yyvaluep->bcls) && qp->destruct) frt_bc_deref((yyvaluep->bcls)); };
1225
+ #line 1240 "src/q_parser.c"
1226
+ break;
1227
+ case 30: /* "boosted_q" */
1228
+ #line 221 "src/q_parser.y"
1229
+ { if ((yyvaluep->query) && qp->destruct) frt_q_deref((yyvaluep->query)); };
1230
+ #line 1245 "src/q_parser.c"
1231
+ break;
1232
+ case 31: /* "q" */
1233
+ #line 221 "src/q_parser.y"
1234
+ { if ((yyvaluep->query) && qp->destruct) frt_q_deref((yyvaluep->query)); };
1235
+ #line 1250 "src/q_parser.c"
1236
+ break;
1237
+ case 32: /* "term_q" */
1238
+ #line 221 "src/q_parser.y"
1239
+ { if ((yyvaluep->query) && qp->destruct) frt_q_deref((yyvaluep->query)); };
1240
+ #line 1255 "src/q_parser.c"
1241
+ break;
1242
+ case 33: /* "wild_q" */
1243
+ #line 221 "src/q_parser.y"
1244
+ { if ((yyvaluep->query) && qp->destruct) frt_q_deref((yyvaluep->query)); };
1245
+ #line 1260 "src/q_parser.c"
1246
+ break;
1247
+ case 34: /* "field_q" */
1248
+ #line 221 "src/q_parser.y"
1249
+ { if ((yyvaluep->query) && qp->destruct) frt_q_deref((yyvaluep->query)); };
1250
+ #line 1265 "src/q_parser.c"
1251
+ break;
1252
+ case 39: /* "phrase_q" */
1253
+ #line 221 "src/q_parser.y"
1254
+ { if ((yyvaluep->query) && qp->destruct) frt_q_deref((yyvaluep->query)); };
1255
+ #line 1270 "src/q_parser.c"
1256
+ break;
1257
+ case 40: /* "ph_words" */
1258
+ #line 224 "src/q_parser.y"
1259
+ { if ((yyvaluep->phrase) && qp->destruct) ph_destroy((yyvaluep->phrase)); };
1260
+ #line 1275 "src/q_parser.c"
1261
+ break;
1262
+ case 41: /* "range_q" */
1263
+ #line 221 "src/q_parser.y"
1264
+ { if ((yyvaluep->query) && qp->destruct) frt_q_deref((yyvaluep->query)); };
1265
+ #line 1280 "src/q_parser.c"
1266
+ break;
1267
+
1268
+ default:
1269
+ break;
1270
+ }
1271
+ }
1272
+
1273
+
1274
+ /* Prevent warnings from -Wmissing-prototypes. */
1275
+
1276
+ #ifdef YYPARSE_PARAM
1277
+ #if defined __STDC__ || defined __cplusplus
1278
+ int yyparse (void *YYPARSE_PARAM);
1279
+ #else
1280
+ int yyparse ();
1281
+ #endif
1282
+ #else /* ! YYPARSE_PARAM */
1283
+ #if defined __STDC__ || defined __cplusplus
1284
+ int yyparse (FrtQParser *qp);
1285
+ #else
1286
+ int yyparse ();
1287
+ #endif
1288
+ #endif /* ! YYPARSE_PARAM */
1289
+
1290
+
1291
+
1292
+
1293
+
1294
+
1295
+ /*----------.
1296
+ | yyparse. |
1297
+ `----------*/
1298
+
1299
+ #ifdef YYPARSE_PARAM
1300
+ #if (defined __STDC__ || defined __C99__FUNC__ \
1301
+ || defined __cplusplus || defined _MSC_VER)
1302
+ int
1303
+ yyparse (void *YYPARSE_PARAM)
1304
+ #else
1305
+ int
1306
+ yyparse (YYPARSE_PARAM)
1307
+ void *YYPARSE_PARAM;
1308
+ #endif
1309
+ #else /* ! YYPARSE_PARAM */
1310
+ #if (defined __STDC__ || defined __C99__FUNC__ \
1311
+ || defined __cplusplus || defined _MSC_VER)
1312
+ int
1313
+ yyparse (FrtQParser *qp)
1314
+ #else
1315
+ int
1316
+ yyparse (qp)
1317
+ FrtQParser *qp;
1318
+ #endif
1319
+ #endif
1320
+ {
1321
+ /* The look-ahead symbol. */
1322
+ int yychar;
1323
+
1324
+ /* The semantic value of the look-ahead symbol. */
1325
+ YYSTYPE yylval;
1326
+
1327
+ /* Number of syntax errors so far. */
1328
+ int yynerrs;
1329
+
1330
+ int yystate;
1331
+ int yyn;
1332
+ int yyresult;
1333
+ /* Number of tokens to shift before error messages enabled. */
1334
+ int yyerrstatus;
1335
+ /* Look-ahead token as an internal (translated) token number. */
1336
+ int yytoken = 0;
1337
+ #if YYERROR_VERBOSE
1338
+ /* Buffer for error messages, and its allocated size. */
1339
+ char yymsgbuf[128];
1340
+ char *yymsg = yymsgbuf;
1341
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
1342
+ #endif
1343
+
1344
+ /* Three stacks and their tools:
1345
+ `yyss': related to states,
1346
+ `yyvs': related to semantic values,
1347
+ `yyls': related to locations.
1348
+
1349
+ Refer to the stacks thru separate pointers, to allow yyoverflow
1350
+ to reallocate them elsewhere. */
1351
+
1352
+ /* The state stack. */
1353
+ yytype_int16 yyssa[YYINITDEPTH];
1354
+ yytype_int16 *yyss = yyssa;
1355
+ yytype_int16 *yyssp;
1356
+
1357
+ /* The semantic value stack. */
1358
+ YYSTYPE yyvsa[YYINITDEPTH];
1359
+ YYSTYPE *yyvs = yyvsa;
1360
+ YYSTYPE *yyvsp;
1361
+
1362
+
1363
+
1364
+ #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
1365
+
1366
+ YYSIZE_T yystacksize = YYINITDEPTH;
1367
+
1368
+ /* The variables used to return semantic value and location from the
1369
+ action routines. */
1370
+ YYSTYPE yyval;
1371
+
1372
+
1373
+ /* The number of symbols on the RHS of the reduced rule.
1374
+ Keep to zero when no symbol should be popped. */
1375
+ int yylen = 0;
1376
+
1377
+ YYDPRINTF ((stderr, "Starting parse\n"));
1378
+
1379
+ yystate = 0;
1380
+ yyerrstatus = 0;
1381
+ yynerrs = 0;
1382
+ yychar = YYEMPTY; /* Cause a token to be read. */
1383
+
1384
+ /* Initialize stack pointers.
1385
+ Waste one element of value and location stack
1386
+ so that they stay on the same level as the state stack.
1387
+ The wasted elements are never initialized. */
1388
+
1389
+ yyssp = yyss;
1390
+ yyvsp = yyvs;
1391
+
1392
+ goto yysetstate;
1393
+
1394
+ /*------------------------------------------------------------.
1395
+ | yynewstate -- Push a new state, which is found in yystate. |
1396
+ `------------------------------------------------------------*/
1397
+ yynewstate:
1398
+ /* In all cases, when you get here, the value and location stacks
1399
+ have just been pushed. So pushing a state here evens the stacks. */
1400
+ yyssp++;
1401
+
1402
+ yysetstate:
1403
+ *yyssp = yystate;
1404
+
1405
+ if (yyss + yystacksize - 1 <= yyssp)
1406
+ {
1407
+ /* Get the current used size of the three stacks, in elements. */
1408
+ YYSIZE_T yysize = yyssp - yyss + 1;
1409
+
1410
+ #ifdef yyoverflow
1411
+ {
1412
+ /* Give user a chance to reallocate the stack. Use copies of
1413
+ these so that the &'s don't force the real ones into
1414
+ memory. */
1415
+ YYSTYPE *yyvs1 = yyvs;
1416
+ yytype_int16 *yyss1 = yyss;
1417
+
1418
+
1419
+ /* Each stack pointer address is followed by the size of the
1420
+ data in use in that stack, in bytes. This used to be a
1421
+ conditional around just the two extra args, but that might
1422
+ be undefined if yyoverflow is a macro. */
1423
+ yyoverflow (YY_("memory exhausted"),
1424
+ &yyss1, yysize * sizeof (*yyssp),
1425
+ &yyvs1, yysize * sizeof (*yyvsp),
1426
+
1427
+ &yystacksize);
1428
+
1429
+ yyss = yyss1;
1430
+ yyvs = yyvs1;
1431
+ }
1432
+ #else /* no yyoverflow */
1433
+ # ifndef YYSTACK_RELOCATE
1434
+ goto yyexhaustedlab;
1435
+ # else
1436
+ /* Extend the stack our own way. */
1437
+ if (YYMAXDEPTH <= yystacksize)
1438
+ goto yyexhaustedlab;
1439
+ yystacksize *= 2;
1440
+ if (YYMAXDEPTH < yystacksize)
1441
+ yystacksize = YYMAXDEPTH;
1442
+
1443
+ {
1444
+ yytype_int16 *yyss1 = yyss;
1445
+ union yyalloc *yyptr =
1446
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
1447
+ if (! yyptr)
1448
+ goto yyexhaustedlab;
1449
+ YYSTACK_RELOCATE (yyss);
1450
+ YYSTACK_RELOCATE (yyvs);
1451
+
1452
+ # undef YYSTACK_RELOCATE
1453
+ if (yyss1 != yyssa)
1454
+ YYSTACK_FREE (yyss1);
1455
+ }
1456
+ # endif
1457
+ #endif /* no yyoverflow */
1458
+
1459
+ yyssp = yyss + yysize - 1;
1460
+ yyvsp = yyvs + yysize - 1;
1461
+
1462
+
1463
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
1464
+ (unsigned long int) yystacksize));
1465
+
1466
+ if (yyss + yystacksize - 1 <= yyssp)
1467
+ YYABORT;
1468
+ }
1469
+
1470
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
1471
+
1472
+ goto yybackup;
1473
+
1474
+ /*-----------.
1475
+ | yybackup. |
1476
+ `-----------*/
1477
+ yybackup:
1478
+
1479
+ /* Do appropriate processing given the current state. Read a
1480
+ look-ahead token if we need one and don't already have one. */
1481
+
1482
+ /* First try to decide what to do without reference to look-ahead token. */
1483
+ yyn = yypact[yystate];
1484
+ if (yyn == YYPACT_NINF)
1485
+ goto yydefault;
1486
+
1487
+ /* Not known => get a look-ahead token if don't already have one. */
1488
+
1489
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
1490
+ if (yychar == YYEMPTY)
1491
+ {
1492
+ YYDPRINTF ((stderr, "Reading a token: "));
1493
+ yychar = YYLEX;
1494
+ }
1495
+
1496
+ if (yychar <= YYEOF)
1497
+ {
1498
+ yychar = yytoken = YYEOF;
1499
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
1500
+ }
1501
+ else
1502
+ {
1503
+ yytoken = YYTRANSLATE (yychar);
1504
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
1505
+ }
1506
+
1507
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
1508
+ detect an error, take that action. */
1509
+ yyn += yytoken;
1510
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
1511
+ goto yydefault;
1512
+ yyn = yytable[yyn];
1513
+ if (yyn <= 0)
1514
+ {
1515
+ if (yyn == 0 || yyn == YYTABLE_NINF)
1516
+ goto yyerrlab;
1517
+ yyn = -yyn;
1518
+ goto yyreduce;
1519
+ }
1520
+
1521
+ if (yyn == YYFINAL)
1522
+ YYACCEPT;
1523
+
1524
+ /* Count tokens shifted since error; after three, turn off error
1525
+ status. */
1526
+ if (yyerrstatus)
1527
+ yyerrstatus--;
1528
+
1529
+ /* Shift the look-ahead token. */
1530
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
1531
+
1532
+ /* Discard the shifted token unless it is eof. */
1533
+ if (yychar != YYEOF)
1534
+ yychar = YYEMPTY;
1535
+
1536
+ yystate = yyn;
1537
+ *++yyvsp = yylval;
1538
+
1539
+ goto yynewstate;
1540
+
1541
+
1542
+ /*-----------------------------------------------------------.
1543
+ | yydefault -- do the default action for the current state. |
1544
+ `-----------------------------------------------------------*/
1545
+ yydefault:
1546
+ yyn = yydefact[yystate];
1547
+ if (yyn == 0)
1548
+ goto yyerrlab;
1549
+ goto yyreduce;
1550
+
1551
+
1552
+ /*-----------------------------.
1553
+ | yyreduce -- Do a reduction. |
1554
+ `-----------------------------*/
1555
+ yyreduce:
1556
+ /* yyn is the number of a rule to reduce with. */
1557
+ yylen = yyr2[yyn];
1558
+
1559
+ /* If YYLEN is nonzero, implement the default value of the action:
1560
+ `$$ = $1'.
1561
+
1562
+ Otherwise, the following line sets YYVAL to garbage.
1563
+ This behavior is undocumented and Bison
1564
+ users should not rely upon it. Assigning to YYVAL
1565
+ unconditionally makes the parser a bit smaller, and it avoids a
1566
+ GCC warning that YYVAL may be used uninitialized. */
1567
+ yyval = yyvsp[1-yylen];
1568
+
1569
+
1570
+ YY_REDUCE_PRINT (yyn);
1571
+ switch (yyn)
1572
+ {
1573
+ case 2:
1574
+ #line 226 "src/q_parser.y"
1575
+ { qp->result = (yyval.query) = NULL; }
1576
+ break;
1577
+
1578
+ case 3:
1579
+ #line 227 "src/q_parser.y"
1580
+ { T qp->result = (yyval.query) = get_bool_q((yyvsp[(1) - (1)].bclss)); E }
1581
+ break;
1582
+
1583
+ case 4:
1584
+ #line 229 "src/q_parser.y"
1585
+ { T (yyval.bclss) = first_cls((yyvsp[(1) - (1)].bcls)); E }
1586
+ break;
1587
+
1588
+ case 5:
1589
+ #line 230 "src/q_parser.y"
1590
+ { T (yyval.bclss) = add_and_cls((yyvsp[(1) - (3)].bclss), (yyvsp[(3) - (3)].bcls)); E }
1591
+ break;
1592
+
1593
+ case 6:
1594
+ #line 231 "src/q_parser.y"
1595
+ { T (yyval.bclss) = add_or_cls((yyvsp[(1) - (3)].bclss), (yyvsp[(3) - (3)].bcls)); E }
1596
+ break;
1597
+
1598
+ case 7:
1599
+ #line 232 "src/q_parser.y"
1600
+ { T (yyval.bclss) = add_default_cls(qp, (yyvsp[(1) - (2)].bclss), (yyvsp[(2) - (2)].bcls)); E }
1601
+ break;
1602
+
1603
+ case 8:
1604
+ #line 234 "src/q_parser.y"
1605
+ { T (yyval.bcls) = get_bool_cls((yyvsp[(2) - (2)].query), FRT_BC_MUST); E }
1606
+ break;
1607
+
1608
+ case 9:
1609
+ #line 235 "src/q_parser.y"
1610
+ { T (yyval.bcls) = get_bool_cls((yyvsp[(2) - (2)].query), FRT_BC_MUST_NOT); E }
1611
+ break;
1612
+
1613
+ case 10:
1614
+ #line 236 "src/q_parser.y"
1615
+ { T (yyval.bcls) = get_bool_cls((yyvsp[(1) - (1)].query), FRT_BC_SHOULD); E }
1616
+ break;
1617
+
1618
+ case 12:
1619
+ #line 239 "src/q_parser.y"
1620
+ { T if ((yyvsp[(1) - (3)].query)) sscanf((yyvsp[(3) - (3)].str),"%f",&((yyvsp[(1) - (3)].query)->boost)); (yyval.query)=(yyvsp[(1) - (3)].query); E }
1621
+ break;
1622
+
1623
+ case 14:
1624
+ #line 242 "src/q_parser.y"
1625
+ { T (yyval.query) = frt_bq_new_max(true, qp->max_clauses); E }
1626
+ break;
1627
+
1628
+ case 15:
1629
+ #line 243 "src/q_parser.y"
1630
+ { T (yyval.query) = get_bool_q((yyvsp[(2) - (3)].bclss)); E }
1631
+ break;
1632
+
1633
+ case 20:
1634
+ #line 249 "src/q_parser.y"
1635
+ { FLDS((yyval.query), get_term_q(qp, field, (yyvsp[(1) - (1)].str))); Y }
1636
+ break;
1637
+
1638
+ case 21:
1639
+ #line 250 "src/q_parser.y"
1640
+ { FLDS((yyval.query), get_fuzzy_q(qp, field, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str))); Y }
1641
+ break;
1642
+
1643
+ case 22:
1644
+ #line 251 "src/q_parser.y"
1645
+ { FLDS((yyval.query), get_fuzzy_q(qp, field, (yyvsp[(1) - (2)].str), NULL)); Y }
1646
+ break;
1647
+
1648
+ case 23:
1649
+ #line 253 "src/q_parser.y"
1650
+ { FLDS((yyval.query), get_wild_q(qp, field, (yyvsp[(1) - (1)].str))); Y }
1651
+ break;
1652
+
1653
+ case 24:
1654
+ #line 255 "src/q_parser.y"
1655
+ { qp_pop_fields(qp); }
1656
+ break;
1657
+
1658
+ case 25:
1659
+ #line 256 "src/q_parser.y"
1660
+ { (yyval.query) = (yyvsp[(3) - (4)].query); }
1661
+ break;
1662
+
1663
+ case 26:
1664
+ #line 257 "src/q_parser.y"
1665
+ { qp_push_fields(qp, qp->all_fields, false); }
1666
+ break;
1667
+
1668
+ case 27:
1669
+ #line 257 "src/q_parser.y"
1670
+ { qp_pop_fields(qp); }
1671
+ break;
1672
+
1673
+ case 28:
1674
+ #line 258 "src/q_parser.y"
1675
+ { (yyval.query) = (yyvsp[(4) - (5)].query); }
1676
+ break;
1677
+
1678
+ case 29:
1679
+ #line 260 "src/q_parser.y"
1680
+ { (yyval.hashset) = first_field(qp, (yyvsp[(1) - (1)].str)); }
1681
+ break;
1682
+
1683
+ case 30:
1684
+ #line 261 "src/q_parser.y"
1685
+ { (yyval.hashset) = add_field(qp, (yyvsp[(3) - (3)].str));}
1686
+ break;
1687
+
1688
+ case 31:
1689
+ #line 263 "src/q_parser.y"
1690
+ { (yyval.query) = get_phrase_q(qp, (yyvsp[(2) - (3)].phrase), NULL); }
1691
+ break;
1692
+
1693
+ case 32:
1694
+ #line 264 "src/q_parser.y"
1695
+ { (yyval.query) = get_phrase_q(qp, (yyvsp[(2) - (5)].phrase), (yyvsp[(5) - (5)].str)); }
1696
+ break;
1697
+
1698
+ case 33:
1699
+ #line 265 "src/q_parser.y"
1700
+ { (yyval.query) = NULL; }
1701
+ break;
1702
+
1703
+ case 34:
1704
+ #line 266 "src/q_parser.y"
1705
+ { (yyval.query) = NULL; (void)(yyvsp[(4) - (4)].str);}
1706
+ break;
1707
+
1708
+ case 35:
1709
+ #line 268 "src/q_parser.y"
1710
+ { (yyval.phrase) = ph_first_word((yyvsp[(1) - (1)].str)); }
1711
+ break;
1712
+
1713
+ case 36:
1714
+ #line 269 "src/q_parer.y"
1715
+ { (yyval.phrase) = ph_first_word(NULL); }
1716
+ break;
1717
+
1718
+ case 37:
1719
+ #line 270 "src/q_parser.y"
1720
+ { (yyval.phrase) = ph_add_word((yyvsp[(1) - (2)].phrase), (yyvsp[(2) - (2)].str)); }
1721
+ break;
1722
+
1723
+ case 38:
1724
+ #line 271 "src/q_parser.y"
1725
+ { (yyval.phrase) = ph_add_word((yyvsp[(1) - (3)].phrase), NULL); }
1726
+ break;
1727
+
1728
+ case 39:
1729
+ #line 272 "src/q_parser.y"
1730
+ { (yyval.phrase) = ph_add_multi_word((yyvsp[(1) - (3)].phrase), (yyvsp[(3) - (3)].str)); }
1731
+ break;
1732
+
1733
+ case 40:
1734
+ #line 274 "src/q_parser.y"
1735
+ { FLDS((yyval.query), get_r_q(qp, field, (yyvsp[(2) - (4)].str), (yyvsp[(3) - (4)].str), true, true)); Y }
1736
+ break;
1737
+
1738
+ case 41:
1739
+ #line 275 "src/q_parser.y"
1740
+ { FLDS((yyval.query), get_r_q(qp, field, (yyvsp[(2) - (4)].str), (yyvsp[(3) - (4)].str), true, false)); Y }
1741
+ break;
1742
+
1743
+ case 42:
1744
+ #line 276 "src/q_parser.y"
1745
+ { FLDS((yyval.query), get_r_q(qp, field, (yyvsp[(2) - (4)].str), (yyvsp[(3) - (4)].str), false, true)); Y }
1746
+ break;
1747
+
1748
+ case 43:
1749
+ #line 277 "src/q_parser.y"
1750
+ { FLDS((yyval.query), get_r_q(qp, field, (yyvsp[(2) - (4)].str), (yyvsp[(3) - (4)].str), false, false)); Y }
1751
+ break;
1752
+
1753
+ case 44:
1754
+ #line 278 "src/q_parser.y"
1755
+ { FLDS((yyval.query), get_r_q(qp, field, NULL,(yyvsp[(2) - (3)].str), false, false)); Y }
1756
+ break;
1757
+
1758
+ case 45:
1759
+ #line 279 "src/q_parser.y"
1760
+ { FLDS((yyval.query), get_r_q(qp, field, NULL,(yyvsp[(2) - (3)].str), false, true)); Y }
1761
+ break;
1762
+
1763
+ case 46:
1764
+ #line 280 "src/q_parser.y"
1765
+ { FLDS((yyval.query), get_r_q(qp, field, (yyvsp[(2) - (3)].str), NULL, true, false)); Y }
1766
+ break;
1767
+
1768
+ case 47:
1769
+ #line 281 "src/q_parser.y"
1770
+ { FLDS((yyval.query), get_r_q(qp, field, (yyvsp[(2) - (3)].str), NULL, false, false)); Y }
1771
+ break;
1772
+
1773
+ case 48:
1774
+ #line 282 "src/q_parser.y"
1775
+ { FLDS((yyval.query), get_r_q(qp, field, NULL,(yyvsp[(2) - (2)].str), false, false)); Y }
1776
+ break;
1777
+
1778
+ case 49:
1779
+ #line 283 "src/q_parser.y"
1780
+ { FLDS((yyval.query), get_r_q(qp, field, NULL,(yyvsp[(3) - (3)].str), false, true)); Y }
1781
+ break;
1782
+
1783
+ case 50:
1784
+ #line 284 "src/q_parser.y"
1785
+ { FLDS((yyval.query), get_r_q(qp, field, (yyvsp[(3) - (3)].str), NULL, true, false)); Y }
1786
+ break;
1787
+
1788
+ case 51:
1789
+ #line 285 "src/q_parser.y"
1790
+ { FLDS((yyval.query), get_r_q(qp, field, (yyvsp[(2) - (2)].str), NULL, false, false)); Y }
1791
+ break;
1792
+
1793
+
1794
+ /* Line 1267 of yacc.c. */
1795
+ #line 1810 "src/q_parser.c"
1796
+ default: break;
1797
+ }
1798
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
1799
+
1800
+ YYPOPSTACK (yylen);
1801
+ yylen = 0;
1802
+ YY_STACK_PRINT (yyss, yyssp);
1803
+
1804
+ *++yyvsp = yyval;
1805
+
1806
+
1807
+ /* Now `shift' the result of the reduction. Determine what state
1808
+ that goes to, based on the state we popped back to and the rule
1809
+ number reduced by. */
1810
+
1811
+ yyn = yyr1[yyn];
1812
+
1813
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
1814
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
1815
+ yystate = yytable[yystate];
1816
+ else
1817
+ yystate = yydefgoto[yyn - YYNTOKENS];
1818
+
1819
+ goto yynewstate;
1820
+
1821
+
1822
+ /*------------------------------------.
1823
+ | yyerrlab -- here on detecting error |
1824
+ `------------------------------------*/
1825
+ yyerrlab:
1826
+ /* If not already recovering from an error, report this error. */
1827
+ if (!yyerrstatus)
1828
+ {
1829
+ ++yynerrs;
1830
+ #if ! YYERROR_VERBOSE
1831
+ yyerror (qp, YY_("syntax error"));
1832
+ #else
1833
+ {
1834
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
1835
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
1836
+ {
1837
+ YYSIZE_T yyalloc = 2 * yysize;
1838
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
1839
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
1840
+ if (yymsg != yymsgbuf)
1841
+ YYSTACK_FREE (yymsg);
1842
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
1843
+ if (yymsg)
1844
+ yymsg_alloc = yyalloc;
1845
+ else
1846
+ {
1847
+ yymsg = yymsgbuf;
1848
+ yymsg_alloc = sizeof yymsgbuf;
1849
+ }
1850
+ }
1851
+
1852
+ if (0 < yysize && yysize <= yymsg_alloc)
1853
+ {
1854
+ (void) yysyntax_error (yymsg, yystate, yychar);
1855
+ yyerror (qp, yymsg);
1856
+ }
1857
+ else
1858
+ {
1859
+ yyerror (qp, YY_("syntax error"));
1860
+ if (yysize != 0)
1861
+ goto yyexhaustedlab;
1862
+ }
1863
+ }
1864
+ #endif
1865
+ }
1866
+
1867
+
1868
+
1869
+ if (yyerrstatus == 3)
1870
+ {
1871
+ /* If just tried and failed to reuse look-ahead token after an
1872
+ error, discard it. */
1873
+
1874
+ if (yychar <= YYEOF)
1875
+ {
1876
+ /* Return failure if at end of input. */
1877
+ if (yychar == YYEOF)
1878
+ YYABORT;
1879
+ }
1880
+ else
1881
+ {
1882
+ yydestruct ("Error: discarding",
1883
+ yytoken, &yylval, qp);
1884
+ yychar = YYEMPTY;
1885
+ }
1886
+ }
1887
+
1888
+ /* Else will try to reuse look-ahead token after shifting the error
1889
+ token. */
1890
+ goto yyerrlab1;
1891
+
1892
+
1893
+ /*---------------------------------------------------.
1894
+ | yyerrorlab -- error raised explicitly by YYERROR. |
1895
+ `---------------------------------------------------*/
1896
+ yyerrorlab:
1897
+
1898
+ /* Pacify compilers like GCC when the user code never invokes
1899
+ YYERROR and the label yyerrorlab therefore never appears in user
1900
+ code. */
1901
+ if (/*CONSTCOND*/ 0)
1902
+ goto yyerrorlab;
1903
+
1904
+ /* Do not reclaim the symbols of the rule which action triggered
1905
+ this YYERROR. */
1906
+ YYPOPSTACK (yylen);
1907
+ yylen = 0;
1908
+ YY_STACK_PRINT (yyss, yyssp);
1909
+ yystate = *yyssp;
1910
+ goto yyerrlab1;
1911
+
1912
+
1913
+ /*-------------------------------------------------------------.
1914
+ | yyerrlab1 -- common code for both syntax error and YYERROR. |
1915
+ `-------------------------------------------------------------*/
1916
+ yyerrlab1:
1917
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
1918
+
1919
+ for (;;)
1920
+ {
1921
+ yyn = yypact[yystate];
1922
+ if (yyn != YYPACT_NINF)
1923
+ {
1924
+ yyn += YYTERROR;
1925
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
1926
+ {
1927
+ yyn = yytable[yyn];
1928
+ if (0 < yyn)
1929
+ break;
1930
+ }
1931
+ }
1932
+
1933
+ /* Pop the current state because it cannot handle the error token. */
1934
+ if (yyssp == yyss)
1935
+ YYABORT;
1936
+
1937
+
1938
+ yydestruct ("Error: popping",
1939
+ yystos[yystate], yyvsp, qp);
1940
+ YYPOPSTACK (1);
1941
+ yystate = *yyssp;
1942
+ YY_STACK_PRINT (yyss, yyssp);
1943
+ }
1944
+
1945
+ if (yyn == YYFINAL)
1946
+ YYACCEPT;
1947
+
1948
+ *++yyvsp = yylval;
1949
+
1950
+
1951
+ /* Shift the error token. */
1952
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
1953
+
1954
+ yystate = yyn;
1955
+ goto yynewstate;
1956
+
1957
+
1958
+ /*-------------------------------------.
1959
+ | yyacceptlab -- YYACCEPT comes here. |
1960
+ `-------------------------------------*/
1961
+ yyacceptlab:
1962
+ yyresult = 0;
1963
+ goto yyreturn;
1964
+
1965
+ /*-----------------------------------.
1966
+ | yyabortlab -- YYABORT comes here. |
1967
+ `-----------------------------------*/
1968
+ yyabortlab:
1969
+ yyresult = 1;
1970
+ goto yyreturn;
1971
+
1972
+ #ifndef yyoverflow
1973
+ /*-------------------------------------------------.
1974
+ | yyexhaustedlab -- memory exhaustion comes here. |
1975
+ `-------------------------------------------------*/
1976
+ yyexhaustedlab:
1977
+ yyerror (qp, YY_("memory exhausted"));
1978
+ yyresult = 2;
1979
+ /* Fall through. */
1980
+ #endif
1981
+
1982
+ yyreturn:
1983
+ if (yychar != YYEOF && yychar != YYEMPTY)
1984
+ yydestruct ("Cleanup: discarding lookahead",
1985
+ yytoken, &yylval, qp);
1986
+ /* Do not reclaim the symbols of the rule which action triggered
1987
+ this YYABORT or YYACCEPT. */
1988
+ YYPOPSTACK (yylen);
1989
+ YY_STACK_PRINT (yyss, yyssp);
1990
+ while (yyssp != yyss)
1991
+ {
1992
+ yydestruct ("Cleanup: popping",
1993
+ yystos[*yyssp], yyvsp, qp);
1994
+ YYPOPSTACK (1);
1995
+ }
1996
+ #ifndef yyoverflow
1997
+ if (yyss != yyssa)
1998
+ YYSTACK_FREE (yyss);
1999
+ #endif
2000
+ #if YYERROR_VERBOSE
2001
+ if (yymsg != yymsgbuf)
2002
+ YYSTACK_FREE (yymsg);
2003
+ #endif
2004
+ /* Make sure YYID is used. */
2005
+ return YYID (yyresult);
2006
+ }
2007
+
2008
+
2009
+ #line 287 "src/q_parser.y"
2010
+
2011
+
2012
+ static const char *special_char = "&:()[]{}!\"~^|<>=*?+-";
2013
+ static const char *not_word = " \t()[]{}!\"~^|<>=";
2014
+
2015
+ /**
2016
+ * +get_word+ gets the next query-word from the query string. A query-word is
2017
+ * basically a string of non-special or escaped special characters. It is
2018
+ * FrtAnalyzer agnostic. It is up to the get_*_q methods to tokenize the word and
2019
+ * turn it into a +Query+. See the documentation for each get_*_q method to
2020
+ * see how it handles tokenization.
2021
+ *
2022
+ * Note that +get_word+ is also responsible for returning field names and
2023
+ * matching the special tokens 'AND', 'NOT', 'REQ' and 'OR'.
2024
+ */
2025
+ static int get_word(YYSTYPE *lvalp, FrtQParser *qp)
2026
+ {
2027
+ bool is_wild = false;
2028
+ int len;
2029
+ char c;
2030
+ char *buf = qp->buf[qp->buf_index];
2031
+ char *bufp = buf;
2032
+ qp->buf_index = (qp->buf_index + 1) % FRT_QP_CONC_WORDS;
2033
+
2034
+ if (qp->dynbuf) {
2035
+ free(qp->dynbuf);
2036
+ qp->dynbuf = NULL;
2037
+ }
2038
+
2039
+ qp->qstrp--; /* need to back up one character */
2040
+
2041
+ while (!strchr(not_word, (c = *qp->qstrp++))) {
2042
+ switch (c) {
2043
+ case '\\':
2044
+ if ((c = *qp->qstrp) == '\0') {
2045
+ *bufp++ = '\\';
2046
+ }
2047
+ else {
2048
+ *bufp++ = c;
2049
+ qp->qstrp++;
2050
+ }
2051
+ break;
2052
+ case ':':
2053
+ if ((*qp->qstrp) == ':') {
2054
+ qp->qstrp++;
2055
+ *bufp++ = ':';
2056
+ *bufp++ = ':';
2057
+ }
2058
+ else {
2059
+ goto get_word_done;
2060
+ }
2061
+ break;
2062
+ case '*': case '?':
2063
+ is_wild = true;
2064
+ /* fall through */
2065
+ default:
2066
+ *bufp++ = c;
2067
+ }
2068
+ /* we've exceeded the static buffer. switch to the dynamic one. The
2069
+ * dynamic buffer is allocated enough space to hold the whole query
2070
+ * string so it's capacity doesn't need to be checked again once
2071
+ * allocated. */
2072
+ if (!qp->dynbuf && ((bufp - buf) == FRT_MAX_WORD_SIZE)) {
2073
+ qp->dynbuf = FRT_ALLOC_AND_ZERO_N(char, strlen(qp->qstr) + 1);
2074
+ strncpy(qp->dynbuf, buf, FRT_MAX_WORD_SIZE);
2075
+ buf = qp->dynbuf;
2076
+ bufp = buf + FRT_MAX_WORD_SIZE;
2077
+ }
2078
+ }
2079
+ get_word_done:
2080
+ qp->qstrp--;
2081
+ /* check for keywords. There are only four so we have a bit of a hack
2082
+ * which just checks for all of them. */
2083
+ *bufp = '\0';
2084
+ len = (int)(bufp - buf);
2085
+ if (qp->use_keywords) {
2086
+ if (len == 3) {
2087
+ if (buf[0] == 'A' && buf[1] == 'N' && buf[2] == 'D') return AND;
2088
+ if (buf[0] == 'N' && buf[1] == 'O' && buf[2] == 'T') return NOT;
2089
+ if (buf[0] == 'R' && buf[1] == 'E' && buf[2] == 'Q') return REQ;
2090
+ }
2091
+ if (len == 2 && buf[0] == 'O' && buf[1] == 'R') return OR;
2092
+ }
2093
+
2094
+ /* found a word so return it. */
2095
+ lvalp->str = buf;
2096
+ if (is_wild) {
2097
+ return WILD_STR;
2098
+ }
2099
+ return QWRD;
2100
+ }
2101
+
2102
+ /**
2103
+ * +yylex+ is the lexing method called by the QueryParser. It breaks the
2104
+ * query up into special characters;
2105
+ *
2106
+ * ( "&:()[]{}!\"~^|<>=*?+-" )
2107
+ *
2108
+ * and tokens;
2109
+ *
2110
+ * - QWRD
2111
+ * - WILD_STR
2112
+ * - AND['AND', '&&']
2113
+ * - OR['OR', '||']
2114
+ * - REQ['REQ', '+']
2115
+ * - NOT['NOT', '-', '~']
2116
+ *
2117
+ * QWRD tokens are query word tokens which are made up of characters other
2118
+ * than the special characters. They can also contain special characters when
2119
+ * escaped with a backslash '\'. WILD_STR is the same as QWRD except that it
2120
+ * may also contain '?' and '*' characters.
2121
+ *
2122
+ * If any of the special chars are seen they will usually be returned straight
2123
+ * away. The exceptions are the wild chars '*' and '?', and '&' which will be
2124
+ * treated as a plain old word character unless followed by another '&'.
2125
+ *
2126
+ * If no special characters or tokens are found then yylex delegates to
2127
+ * +get_word+ which will fetch the next query-word.
2128
+ */
2129
+ static int yylex(YYSTYPE *lvalp, FrtQParser *qp)
2130
+ {
2131
+ char c, nc;
2132
+
2133
+ while ((c=*qp->qstrp++) == ' ' || c == '\t') {
2134
+ }
2135
+
2136
+ if (c == '\0') return 0;
2137
+
2138
+ if (strchr(special_char, c)) { /* comment */
2139
+ nc = *qp->qstrp;
2140
+ switch (c) {
2141
+ case '-': case '!': return NOT;
2142
+ case '+': return REQ;
2143
+ case '*':
2144
+ if (nc == ':') return c;
2145
+ break;
2146
+ case '?':
2147
+ break;
2148
+ case '&':
2149
+ if (nc == '&') {
2150
+ qp->qstrp++;
2151
+ return AND;
2152
+ }
2153
+ break; /* Don't return single & character. Use in word. */
2154
+ case '|':
2155
+ if (nc == '|') {
2156
+ qp->qstrp++;
2157
+ return OR;
2158
+ }
2159
+ default:
2160
+ return c;
2161
+ }
2162
+ }
2163
+
2164
+ return get_word(lvalp, qp);
2165
+ }
2166
+
2167
+ /**
2168
+ * yyerror gets called if there is an parse error with the yacc parser.
2169
+ * It is responsible for clearing any memory that was allocated during the
2170
+ * parsing process.
2171
+ */
2172
+ static int yyerror(FrtQParser *qp, char const *msg)
2173
+ {
2174
+ qp->destruct = true;
2175
+ if (!qp->handle_parse_errors) {
2176
+ char buf[1024];
2177
+ buf[1023] = '\0';
2178
+ strncpy(buf, qp->qstr, 1023);
2179
+ if (qp->clean_str) {
2180
+ free(qp->qstr);
2181
+ }
2182
+ frt_mutex_unlock(&qp->mutex);
2183
+ snprintf(frt_xmsg_buffer, FRT_XMSG_BUFFER_SIZE,
2184
+ "couldn't parse query ``%s''. Error message "
2185
+ " was %s", buf, (char *)msg);
2186
+ }
2187
+ while (qp->fields_top->next != NULL) {
2188
+ qp_pop_fields(qp);
2189
+ }
2190
+ return 0;
2191
+ }
2192
+
2193
+ #define BQ(query) ((FrtBooleanQuery *)(query))
2194
+
2195
+ /**
2196
+ * The QueryParser caches a tokenizer for each field so that it doesn't need
2197
+ * to allocate a new tokenizer for each term in the query. This would be quite
2198
+ * expensive as tokenizers use quite a large hunk of memory.
2199
+ *
2200
+ * This method returns the query parser for a particular field and sets it up
2201
+ * with the text to be tokenized.
2202
+ */
2203
+ static FrtTokenStream *get_cached_ts(FrtQParser *qp, FrtSymbol field, char *text)
2204
+ {
2205
+ FrtTokenStream *ts;
2206
+ if (frt_hs_exists(qp->tokenized_fields, (void *)field)) {
2207
+ ts = (FrtTokenStream *)frt_h_get(qp->ts_cache, (void *)field);
2208
+ if (!ts) {
2209
+ ts = frt_a_get_ts(qp->analyzer, field, text);
2210
+ frt_h_set(qp->ts_cache, (void *)field, ts);
2211
+ }
2212
+ else {
2213
+ ts->reset(ts, text);
2214
+ }
2215
+ }
2216
+ else {
2217
+ ts = qp->non_tokenizer;
2218
+ ts->reset(ts, text);
2219
+ }
2220
+ return ts;
2221
+ }
2222
+
2223
+ /**
2224
+ * Turns a BooleanClause array into a BooleanQuery. It will optimize the query
2225
+ * if 0 or 1 clauses are present to NULL or the actual query in the clause
2226
+ * respectively.
2227
+ */
2228
+ static FrtQuery *get_bool_q(BCArray *bca)
2229
+ {
2230
+ FrtQuery *q;
2231
+ const int clause_count = bca->size;
2232
+
2233
+ if (clause_count == 0) {
2234
+ q = NULL;
2235
+ free(bca->clauses);
2236
+ }
2237
+ else if (clause_count == 1) {
2238
+ FrtBooleanClause *bc = bca->clauses[0];
2239
+ if (bc->is_prohibited) {
2240
+ q = frt_bq_new(false);
2241
+ frt_bq_add_query_nr(q, bc->query, FRT_BC_MUST_NOT);
2242
+ frt_bq_add_query_nr(q, frt_maq_new(), FRT_BC_MUST);
2243
+ }
2244
+ else {
2245
+ q = bc->query;
2246
+ }
2247
+ free(bc);
2248
+ free(bca->clauses);
2249
+ }
2250
+ else {
2251
+ q = frt_bq_new(false);
2252
+ /* copy clauses into query */
2253
+
2254
+ BQ(q)->clause_cnt = clause_count;
2255
+ BQ(q)->clause_capa = bca->capa;
2256
+ free(BQ(q)->clauses);
2257
+ BQ(q)->clauses = bca->clauses;
2258
+ }
2259
+ free(bca);
2260
+ return q;
2261
+ }
2262
+
2263
+ /**
2264
+ * Base method for appending BooleanClauses to a BooleanClause array. This
2265
+ * method doesn't care about the type of clause (MUST, SHOULD, MUST_NOT).
2266
+ */
2267
+ static void bca_add_clause(BCArray *bca, FrtBooleanClause *clause)
2268
+ {
2269
+ if (bca->size >= bca->capa) {
2270
+ bca->capa <<= 1;
2271
+ FRT_REALLOC_N(bca->clauses, FrtBooleanClause *, bca->capa);
2272
+ }
2273
+ bca->clauses[bca->size] = clause;
2274
+ bca->size++;
2275
+ }
2276
+
2277
+ /**
2278
+ * Add the first clause to a BooleanClause array. This method is also
2279
+ * responsible for allocating a new BooleanClause array.
2280
+ */
2281
+ static BCArray *first_cls(FrtBooleanClause *clause)
2282
+ {
2283
+ BCArray *bca = FRT_ALLOC_AND_ZERO(BCArray);
2284
+ bca->capa = BCA_INIT_CAPA;
2285
+ bca->clauses = FRT_ALLOC_N(FrtBooleanClause *, BCA_INIT_CAPA);
2286
+ if (clause) {
2287
+ bca_add_clause(bca, clause);
2288
+ }
2289
+ return bca;
2290
+ }
2291
+
2292
+ /**
2293
+ * Add AND clause to the BooleanClause array. The means that it will set the
2294
+ * clause being added and the previously added clause from SHOULD clauses to
2295
+ * MUST clauses. (If they are currently MUST_NOT clauses they stay as they
2296
+ * are.)
2297
+ */
2298
+ static BCArray *add_and_cls(BCArray *bca, FrtBooleanClause *clause)
2299
+ {
2300
+ if (clause) {
2301
+ if (bca->size == 1) {
2302
+ if (!bca->clauses[0]->is_prohibited) {
2303
+ frt_bc_set_occur(bca->clauses[0], FRT_BC_MUST);
2304
+ }
2305
+ }
2306
+ if (!clause->is_prohibited) {
2307
+ frt_bc_set_occur(clause, FRT_BC_MUST);
2308
+ }
2309
+ bca_add_clause(bca, clause);
2310
+ }
2311
+ return bca;
2312
+ }
2313
+
2314
+ /**
2315
+ * Add SHOULD clause to the BooleanClause array.
2316
+ */
2317
+ static BCArray *add_or_cls(BCArray *bca, FrtBooleanClause *clause)
2318
+ {
2319
+ if (clause) {
2320
+ bca_add_clause(bca, clause);
2321
+ }
2322
+ return bca;
2323
+ }
2324
+
2325
+ /**
2326
+ * Add AND or OR clause to the BooleanClause array, depending on the default
2327
+ * clause type.
2328
+ */
2329
+ static BCArray *add_default_cls(FrtQParser *qp, BCArray *bca,
2330
+ FrtBooleanClause *clause)
2331
+ {
2332
+ if (qp->or_default) {
2333
+ add_or_cls(bca, clause);
2334
+ }
2335
+ else {
2336
+ add_and_cls(bca, clause);
2337
+ }
2338
+ return bca;
2339
+ }
2340
+
2341
+ /**
2342
+ * destroy array of BooleanClauses
2343
+ */
2344
+ static void bca_destroy(BCArray *bca)
2345
+ {
2346
+ int i;
2347
+ for (i = 0; i < bca->size; i++) {
2348
+ frt_bc_deref(bca->clauses[i]);
2349
+ }
2350
+ free(bca->clauses);
2351
+ free(bca);
2352
+ }
2353
+
2354
+ /**
2355
+ * Turn a query into a BooleanClause for addition to a BooleanQuery.
2356
+ */
2357
+ static FrtBooleanClause *get_bool_cls(FrtQuery *q, FrtBCType occur)
2358
+ {
2359
+ if (q) {
2360
+ return frt_bc_new(q, occur);
2361
+ }
2362
+ else {
2363
+ return NULL;
2364
+ }
2365
+ }
2366
+
2367
+ /**
2368
+ * Create a TermQuery. The word will be tokenized and if the tokenization
2369
+ * produces more than one token, a PhraseQuery will be returned. For example,
2370
+ * if the word is dbalmain@gmail.com and a LetterTokenizer is used then a
2371
+ * PhraseQuery "dbalmain gmail com" will be returned which is actually exactly
2372
+ * what we want as it will match any documents containing the same email
2373
+ * address and tokenized with the same tokenizer.
2374
+ */
2375
+ static FrtQuery *get_term_q(FrtQParser *qp, FrtSymbol field, char *word)
2376
+ {
2377
+ FrtQuery *q;
2378
+ FrtToken *token;
2379
+ FrtTokenStream *stream = get_cached_ts(qp, field, word);
2380
+
2381
+ if ((token = frt_ts_next(stream)) == NULL) {
2382
+ q = NULL;
2383
+ }
2384
+ else {
2385
+ q = frt_tq_new(field, token->text);
2386
+ if ((token = frt_ts_next(stream)) != NULL) {
2387
+ /* Less likely case, destroy the term query and create a
2388
+ * phrase query instead */
2389
+ FrtQuery *phq = frt_phq_new(field);
2390
+ frt_phq_add_term(phq, ((FrtTermQuery *)q)->term, 0);
2391
+ q->destroy_i(q);
2392
+ q = phq;
2393
+ do {
2394
+ if (token->pos_inc) {
2395
+ frt_phq_add_term(q, token->text, token->pos_inc);
2396
+ /* add some slop since single term was expected */
2397
+ ((FrtPhraseQuery *)q)->slop++;
2398
+ }
2399
+ else {
2400
+ frt_phq_append_multi_term(q, token->text);
2401
+ }
2402
+ } while ((token = frt_ts_next(stream)) != NULL);
2403
+ }
2404
+ }
2405
+ return q;
2406
+ }
2407
+
2408
+ /**
2409
+ * Create a FuzzyQuery. The word will be tokenized and only the first token
2410
+ * will be used. If there are any more tokens after tokenization, they will be
2411
+ * ignored.
2412
+ */
2413
+ static FrtQuery *get_fuzzy_q(FrtQParser *qp, FrtSymbol field, char *word, char *slop_str)
2414
+ {
2415
+ FrtQuery *q;
2416
+ FrtToken *token;
2417
+ FrtTokenStream *stream = get_cached_ts(qp, field, word);
2418
+
2419
+ if ((token = frt_ts_next(stream)) == NULL) {
2420
+ q = NULL;
2421
+ }
2422
+ else {
2423
+ /* it only makes sense to find one term in a fuzzy query */
2424
+ float slop = frt_qp_default_fuzzy_min_sim;
2425
+ if (slop_str) {
2426
+ sscanf(slop_str, "%f", &slop);
2427
+ }
2428
+ q = frt_fuzq_new_conf(field, token->text, slop, frt_qp_default_fuzzy_pre_len,
2429
+ qp->max_clauses);
2430
+ }
2431
+ return q;
2432
+ }
2433
+
2434
+ /**
2435
+ * Downcase a string taking locale into account and works for multibyte
2436
+ * character sets.
2437
+ */
2438
+ static char *lower_str(char *str)
2439
+ {
2440
+ const int max_len = (int)strlen(str) + 1;
2441
+ int cnt;
2442
+ wchar_t *wstr = FRT_ALLOC_N(wchar_t, max_len);
2443
+ if ((cnt = mbstowcs(wstr, str, max_len)) > 0) {
2444
+ wchar_t *w = wstr;
2445
+ while (*w) {
2446
+ *w = towlower(*w);
2447
+ w++;
2448
+ }
2449
+ wcstombs(str, wstr, max_len);
2450
+ }
2451
+ else {
2452
+ char *s = str;
2453
+ while (*s) {
2454
+ *s = tolower(*s);
2455
+ s++;
2456
+ }
2457
+ }
2458
+ free(wstr);
2459
+ str[max_len] = '\0';
2460
+ return str;
2461
+ }
2462
+
2463
+ /**
2464
+ * Create a WildCardQuery. No tokenization will be performed on the pattern
2465
+ * but the pattern will be downcased if +qp->wild_lower+ is set to true and
2466
+ * the field in question is a tokenized field.
2467
+ *
2468
+ * Note: this method will not always return a WildCardQuery. It could be
2469
+ * optimized to a MatchAllQuery if the pattern is '*' or a PrefixQuery if the
2470
+ * only wild char (*, ?) in the pattern is a '*' at the end of the pattern.
2471
+ */
2472
+ static FrtQuery *get_wild_q(FrtQParser *qp, FrtSymbol field, char *pattern)
2473
+ {
2474
+ FrtQuery *q;
2475
+ bool is_prefix = false;
2476
+ char *p;
2477
+ int len = (int)strlen(pattern);
2478
+
2479
+ if (qp->wild_lower
2480
+ && (!qp->tokenized_fields || frt_hs_exists(qp->tokenized_fields, (void *)field))) {
2481
+ lower_str(pattern);
2482
+ }
2483
+
2484
+ /* simplify the wildcard query to a prefix query if possible. Basically a
2485
+ * prefix query is any wildcard query that has a '*' as the last character
2486
+ * and no other wildcard characters before it. "*" by itself will expand
2487
+ * to a MatchAllQuery */
2488
+ if (strcmp(pattern, "*") == 0) {
2489
+ return frt_maq_new();
2490
+ }
2491
+ if (pattern[len - 1] == '*') {
2492
+ is_prefix = true;
2493
+ for (p = &pattern[len - 2]; p >= pattern; p--) {
2494
+ if (*p == '*' || *p == '?') {
2495
+ is_prefix = false;
2496
+ break;
2497
+ }
2498
+ }
2499
+ }
2500
+ if (is_prefix) {
2501
+ /* chop off the '*' temporarily to create the query */
2502
+ pattern[len - 1] = 0;
2503
+ q = frt_prefixq_new(field, pattern);
2504
+ pattern[len - 1] = '*';
2505
+ }
2506
+ else {
2507
+ q = frt_wcq_new(field, pattern);
2508
+ }
2509
+ FrtMTQMaxTerms(q) = qp->max_clauses;
2510
+ return q;
2511
+ }
2512
+
2513
+ /**
2514
+ * Adds another field to the top of the FieldStack.
2515
+ */
2516
+ static FrtHashSet *add_field(FrtQParser *qp, const char *field_name)
2517
+ {
2518
+ FrtSymbol field = rb_intern(field_name);
2519
+ if (qp->allow_any_fields || frt_hs_exists(qp->all_fields, (void *)field)) {
2520
+ frt_hs_add(qp->fields, (void *)field);
2521
+ }
2522
+ return qp->fields;
2523
+ }
2524
+
2525
+ /**
2526
+ * The method gets called when a field modifier ("field1|field2:") is seen. It
2527
+ * will push a new FieldStack object onto the stack and add +field+ to its
2528
+ * fields set.
2529
+ */
2530
+ static FrtHashSet *first_field(FrtQParser *qp, const char *field_name)
2531
+ {
2532
+ qp_push_fields(qp, frt_hs_new_ptr(NULL), true);
2533
+ return add_field(qp, field_name);
2534
+ }
2535
+
2536
+ /**
2537
+ * Destroy a phrase object freeing all allocated memory.
2538
+ */
2539
+ static void ph_destroy(Phrase *self)
2540
+ {
2541
+ int i;
2542
+ for (i = 0; i < self->size; i++) {
2543
+ frt_ary_destroy(self->positions[i].terms, &free);
2544
+ }
2545
+ free(self->positions);
2546
+ free(self);
2547
+ }
2548
+
2549
+
2550
+ /**
2551
+ * Allocate a new Phrase object
2552
+ */
2553
+ static Phrase *ph_new()
2554
+ {
2555
+ Phrase *self = FRT_ALLOC_AND_ZERO(Phrase);
2556
+ self->capa = PHRASE_INIT_CAPA;
2557
+ self->positions = FRT_ALLOC_AND_ZERO_N(FrtPhrasePosition, PHRASE_INIT_CAPA);
2558
+ return self;
2559
+ }
2560
+
2561
+ /**
2562
+ * Add the first word to the phrase. This method is also in charge of
2563
+ * allocating a new Phrase object.
2564
+ */
2565
+ static Phrase *ph_first_word(char *word)
2566
+ {
2567
+ Phrase *self = ph_new();
2568
+ if (word) { /* no point in adding NULL in start */
2569
+ self->positions[0].terms = frt_ary_new_type_capa(char *, 1);
2570
+ frt_ary_push(self->positions[0].terms, frt_estrdup(word));
2571
+ self->size = 1;
2572
+ }
2573
+ return self;
2574
+ }
2575
+
2576
+ /**
2577
+ * Add a new word to the Phrase
2578
+ */
2579
+ static Phrase *ph_add_word(Phrase *self, char *word)
2580
+ {
2581
+ if (word) {
2582
+ const int index = self->size;
2583
+ FrtPhrasePosition *pp = self->positions;
2584
+ if (index >= self->capa) {
2585
+ self->capa <<= 1;
2586
+ FRT_REALLOC_N(pp, FrtPhrasePosition, self->capa);
2587
+ self->positions = pp;
2588
+ }
2589
+ pp[index].pos = self->pos_inc;
2590
+ pp[index].terms = frt_ary_new_type_capa(char *, 1);
2591
+ frt_ary_push(pp[index].terms, frt_estrdup(word));
2592
+ self->size++;
2593
+ self->pos_inc = 0;
2594
+ }
2595
+ else {
2596
+ self->pos_inc++;
2597
+ }
2598
+ return self;
2599
+ }
2600
+
2601
+ /**
2602
+ * Adds a word to the Phrase object in the same position as the previous word
2603
+ * added to the Phrase. This will later be turned into a multi-PhraseQuery.
2604
+ */
2605
+ static Phrase *ph_add_multi_word(Phrase *self, char *word)
2606
+ {
2607
+ const int index = self->size - 1;
2608
+ FrtPhrasePosition *pp = self->positions;
2609
+
2610
+ if (word) {
2611
+ frt_ary_push(pp[index].terms, frt_estrdup(word));
2612
+ }
2613
+ return self;
2614
+ }
2615
+
2616
+ /**
2617
+ * Build a phrase query for a single field. It might seem like a better idea
2618
+ * to build the PhraseQuery once and duplicate it for each field but this
2619
+ * would be buggy in the case of PerFieldAnalyzers in which case a different
2620
+ * tokenizer could be used for each field.
2621
+ *
2622
+ * Note that the query object returned by this method is not always a
2623
+ * PhraseQuery. If there is only one term in the query then the query is
2624
+ * simplified to a TermQuery. If there are multiple terms but only a single
2625
+ * position, then a MultiTermQuery is retured.
2626
+ *
2627
+ * Note that each word in the query gets tokenized. Unlike get_term_q, if the
2628
+ * word gets tokenized into more than one token, the rest of the tokens are
2629
+ * ignored. For example, if you have the phrase;
2630
+ *
2631
+ * "email: dbalmain@gmail.com"
2632
+ *
2633
+ * the Phrase object will contain two positions with the words 'email:' and
2634
+ * 'dbalmain@gmail.com'. Now, if you are using a LetterTokenizer then the
2635
+ * second word will be tokenized into the tokens ['dbalmain', 'gmail', 'com']
2636
+ * and only the first token will be used, so the resulting phrase query will
2637
+ * actually look like this;
2638
+ *
2639
+ * "email dbalmain"
2640
+ *
2641
+ * This problem can easily be solved by using the StandardTokenizer or any
2642
+ * custom tokenizer which will leave dbalmain@gmail.com as a single token.
2643
+ */
2644
+ static FrtQuery *get_phrase_query(FrtQParser *qp, FrtSymbol field, Phrase *phrase, char *slop_str)
2645
+ {
2646
+ const int pos_cnt = phrase->size;
2647
+ FrtQuery *q = NULL;
2648
+
2649
+ if (pos_cnt == 1) {
2650
+ char **words = phrase->positions[0].terms;
2651
+ const int word_count = frt_ary_size(words);
2652
+ if (word_count == 1) {
2653
+ q = get_term_q(qp, field, words[0]);
2654
+ }
2655
+ else {
2656
+ int i;
2657
+ int term_cnt = 0;
2658
+ FrtToken *token;
2659
+ char *last_word = NULL;
2660
+
2661
+ for (i = 0; i < word_count; i++) {
2662
+ token = frt_ts_next(get_cached_ts(qp, field, words[i]));
2663
+ if (token) {
2664
+ free(words[i]);
2665
+ last_word = words[i] = frt_estrdup(token->text);
2666
+ ++term_cnt;
2667
+ }
2668
+ else {
2669
+ /* empty words will later be ignored */
2670
+ words[i][0] = '\0';
2671
+ }
2672
+ }
2673
+
2674
+ switch (term_cnt) {
2675
+ case 0:
2676
+ q = frt_bq_new(false);
2677
+ break;
2678
+ case 1:
2679
+ q = frt_tq_new(field, last_word);
2680
+ break;
2681
+ default:
2682
+ q = frt_multi_tq_new_conf(field, term_cnt, 0.0);
2683
+ for (i = 0; i < word_count; i++) {
2684
+ /* ignore empty words */
2685
+ if (words[i][0]) {
2686
+ frt_multi_tq_add_term(q, words[i]);
2687
+ }
2688
+ }
2689
+ break;
2690
+ }
2691
+ }
2692
+ }
2693
+ else if (pos_cnt > 1) {
2694
+ FrtToken *token;
2695
+ FrtTokenStream *stream;
2696
+ int i, j;
2697
+ int pos_inc = 0;
2698
+ q = frt_phq_new(field);
2699
+ if (slop_str) {
2700
+ int slop;
2701
+ sscanf(slop_str,"%d",&slop);
2702
+ ((FrtPhraseQuery *)q)->slop = slop;
2703
+ }
2704
+
2705
+ for (i = 0; i < pos_cnt; i++) {
2706
+ char **words = phrase->positions[i].terms;
2707
+ const int word_count = frt_ary_size(words);
2708
+ if (pos_inc) {
2709
+ ((FrtPhraseQuery *)q)->slop++;
2710
+ }
2711
+ pos_inc += phrase->positions[i].pos + 1; /* Actually holds pos_inc*/
2712
+
2713
+ if (word_count == 1) {
2714
+ stream = get_cached_ts(qp, field, words[0]);
2715
+ while ((token = frt_ts_next(stream))) {
2716
+ if (token->pos_inc) {
2717
+ frt_phq_add_term(q, token->text,
2718
+ pos_inc ? pos_inc : token->pos_inc);
2719
+ }
2720
+ else {
2721
+ frt_phq_append_multi_term(q, token->text);
2722
+ ((FrtPhraseQuery *)q)->slop++;
2723
+ }
2724
+ pos_inc = 0;
2725
+ }
2726
+ }
2727
+ else {
2728
+ bool added_position = false;
2729
+
2730
+ for (j = 0; j < word_count; j++) {
2731
+ stream = get_cached_ts(qp, field, words[j]);
2732
+ if ((token = frt_ts_next(stream))) {
2733
+ if (!added_position) {
2734
+ frt_phq_add_term(q, token->text,
2735
+ pos_inc ? pos_inc : token->pos_inc);
2736
+ added_position = true;
2737
+ pos_inc = 0;
2738
+ }
2739
+ else {
2740
+ frt_phq_append_multi_term(q, token->text);
2741
+ }
2742
+ }
2743
+ }
2744
+ }
2745
+ }
2746
+ }
2747
+ return q;
2748
+ }
2749
+
2750
+ /**
2751
+ * Get a phrase query from the Phrase object. The Phrase object is built up by
2752
+ * the query parser as the all PhraseQuery didn't work well for this. Once the
2753
+ * PhraseQuery has been built the Phrase object needs to be destroyed.
2754
+ */
2755
+ static FrtQuery *get_phrase_q(FrtQParser *qp, Phrase *phrase, char *slop_str)
2756
+ {
2757
+ FrtQuery *volatile q = NULL;
2758
+ FLDS(q, get_phrase_query(qp, field, phrase, slop_str));
2759
+ ph_destroy(phrase);
2760
+ return q;
2761
+ }
2762
+
2763
+ /**
2764
+ * Gets a RangeQuery object.
2765
+ *
2766
+ * Just like with WildCardQuery, RangeQuery needs to downcase its terms if the
2767
+ * tokenizer also downcased its terms.
2768
+ */
2769
+ static FrtQuery *get_r_q(FrtQParser *qp, FrtSymbol field, char *from, char *to, bool inc_lower, bool inc_upper)
2770
+ {
2771
+ FrtQuery *rq;
2772
+ if (qp->wild_lower
2773
+ && (!qp->tokenized_fields || frt_hs_exists(qp->tokenized_fields, (void *)field))) {
2774
+ if (from) {
2775
+ lower_str(from);
2776
+ }
2777
+ if (to) {
2778
+ lower_str(to);
2779
+ }
2780
+ }
2781
+ /*
2782
+ * terms don't get tokenized as it doesn't really make sense to do so for
2783
+ * range queries.
2784
+
2785
+ if (from) {
2786
+ FrtTokenStream *stream = get_cached_ts(qp, field, from);
2787
+ FrtToken *token = frt_ts_next(stream);
2788
+ from = token ? frt_estrdup(token->text) : NULL;
2789
+ }
2790
+ if (to) {
2791
+ FrtTokenStream *stream = get_cached_ts(qp, field, to);
2792
+ FrtToken *token = frt_ts_next(stream);
2793
+ to = token ? frt_estrdup(token->text) : NULL;
2794
+ }
2795
+ */
2796
+
2797
+ rq = qp->use_typed_range_query ?
2798
+ frt_trq_new(field, from, to, inc_lower, inc_upper) :
2799
+ frt_rq_new(field, from, to, inc_lower, inc_upper);
2800
+ return rq;
2801
+ }
2802
+
2803
+ /**
2804
+ * Every time the query parser sees a new field modifier ("field1|field2:")
2805
+ * it pushes a new FieldStack object onto the stack and sets its fields to the
2806
+ * fields specified in the fields modifier. If the field modifier is '*',
2807
+ * fs->fields is set to all_fields. fs->fields is set to +qp->def_field+ at
2808
+ * the bottom of the stack (ie the very first set of fields pushed onto the
2809
+ * stack).
2810
+ */
2811
+ static void qp_push_fields(FrtQParser *self, FrtHashSet *fields, bool destroy)
2812
+ {
2813
+ FrtFieldStack *fs = FRT_ALLOC(FrtFieldStack);
2814
+
2815
+ fs->next = self->fields_top;
2816
+ fs->fields = fields;
2817
+ fs->destroy = destroy;
2818
+
2819
+ self->fields_top = fs;
2820
+ self->fields = fields;
2821
+ }
2822
+
2823
+ /**
2824
+ * Pops the top of the fields stack and frees any memory used by it. This will
2825
+ * get called when query modified by a field modifier ("field1|field2:") has
2826
+ * been fully parsed and the field specifier no longer applies.
2827
+ */
2828
+ static void qp_pop_fields(FrtQParser *self)
2829
+ {
2830
+ FrtFieldStack *fs = self->fields_top;
2831
+
2832
+ if (fs->destroy) {
2833
+ frt_hs_destroy(fs->fields);
2834
+ }
2835
+ self->fields_top = fs->next;
2836
+ if (self->fields_top) {
2837
+ self->fields = self->fields_top->fields;
2838
+ }
2839
+ free(fs);
2840
+ }
2841
+
2842
+ /**
2843
+ * Free all memory allocated by the QueryParser.
2844
+ */
2845
+ void frt_qp_destroy(FrtQParser *self)
2846
+ {
2847
+ if (self->tokenized_fields != self->all_fields) {
2848
+ frt_hs_destroy(self->tokenized_fields);
2849
+ }
2850
+ if (self->def_fields != self->all_fields) {
2851
+ frt_hs_destroy(self->def_fields);
2852
+ }
2853
+ frt_hs_destroy(self->all_fields);
2854
+
2855
+ qp_pop_fields(self);
2856
+ assert(NULL == self->fields_top);
2857
+
2858
+ frt_h_destroy(self->ts_cache);
2859
+ frt_tk_destroy(self->non_tokenizer);
2860
+ frt_a_deref(self->analyzer);
2861
+ free(self);
2862
+ }
2863
+
2864
+ /**
2865
+ * Creates a new QueryParser setting all boolean parameters to their defaults.
2866
+ * If +def_fields+ is NULL then +all_fields+ is used in place of +def_fields+.
2867
+ * Not also that this method ensures that all fields that exist in
2868
+ * +def_fields+ must also exist in +all_fields+. This should make sense.
2869
+ */
2870
+ FrtQParser *frt_qp_new(FrtAnalyzer *analyzer)
2871
+ {
2872
+ FrtQParser *self = FRT_ALLOC(FrtQParser);
2873
+ self->or_default = true;
2874
+ self->wild_lower = true;
2875
+ self->clean_str = false;
2876
+ self->max_clauses = FRT_QP_MAX_CLAUSES;
2877
+ self->handle_parse_errors = false;
2878
+ self->allow_any_fields = false;
2879
+ self->use_keywords = true;
2880
+ self->use_typed_range_query = false;
2881
+ self->def_slop = 0;
2882
+
2883
+ self->def_fields = frt_hs_new_ptr(NULL);
2884
+ self->all_fields = frt_hs_new_ptr(NULL);
2885
+ self->tokenized_fields = frt_hs_new_ptr(NULL);
2886
+ self->fields_top = NULL;
2887
+
2888
+ qp_push_fields(self, self->def_fields, false);
2889
+
2890
+ self->analyzer = analyzer;
2891
+ self->ts_cache = frt_h_new_ptr((frt_free_ft)&frt_ts_deref);
2892
+ self->buf_index = 0;
2893
+ self->dynbuf = NULL;
2894
+ self->non_tokenizer = frt_non_tokenizer_new();
2895
+ frt_mutex_init(&self->mutex, NULL);
2896
+ return self;
2897
+ }
2898
+
2899
+ void frt_qp_add_field(FrtQParser *self, FrtSymbol field, bool is_default, bool is_tokenized)
2900
+ {
2901
+ frt_hs_add(self->all_fields, (void *)field);
2902
+ if (is_default) {
2903
+ frt_hs_add(self->def_fields, (void *)field);
2904
+ }
2905
+ if (is_tokenized) {
2906
+ frt_hs_add(self->tokenized_fields, (void *)field);
2907
+ }
2908
+ }
2909
+
2910
+ /* these chars have meaning within phrases */
2911
+ static const char *PHRASE_CHARS = "<>|\"";
2912
+
2913
+ /**
2914
+ * +str_insert_char+ inserts a character at the beginning of a string by
2915
+ * shifting the rest of the string right.
2916
+ */
2917
+ static void str_insert_char(char *str, int len, char chr)
2918
+ {
2919
+ memmove(str+1, str, len*sizeof(char));
2920
+ *str = chr;
2921
+ }
2922
+
2923
+ /**
2924
+ * +frt_qp_clean_str+ basically scans the query string and ensures that all open
2925
+ * and close parentheses '()' and quotes '"' are balanced. It does this by
2926
+ * inserting or appending extra parentheses or quotes to the string. This
2927
+ * obviously won't necessarily be exactly what the user wanted but we are
2928
+ * never going to know that anyway. The main job of this method is to help the
2929
+ * query at least parse correctly.
2930
+ *
2931
+ * It also checks that all special characters within phrases (ie between
2932
+ * quotes) are escaped correctly unless they have meaning within a phrase
2933
+ * ( <>,|," ). Note that '<' and '>' will also be escaped unless the appear
2934
+ * together like so; '<>'.
2935
+ */
2936
+ char *frt_qp_clean_str(char *str)
2937
+ {
2938
+ int b, pb = -1;
2939
+ int br_cnt = 0;
2940
+ bool quote_open = false;
2941
+ char *sp, *nsp;
2942
+
2943
+ /* leave a little extra */
2944
+ char *new_str = FRT_ALLOC_N(char, strlen(str)*2 + 1);
2945
+
2946
+ for (sp = str, nsp = new_str; *sp; sp++) {
2947
+ b = *sp;
2948
+ /* ignore escaped characters */
2949
+ if (pb == '\\') {
2950
+ if (quote_open && strrchr(PHRASE_CHARS, b)) {
2951
+ *nsp++ = '\\'; /* this was left off the first time through */
2952
+ }
2953
+ *nsp++ = b;
2954
+ /* \ has escaped itself so has no power. Assign pb random char 'r' */
2955
+ pb = ((b == '\\') ? 'r' : b);
2956
+ continue;
2957
+ }
2958
+ switch (b) {
2959
+ case '\\':
2960
+ if (!quote_open) { /* We do our own escaping below */
2961
+ *nsp++ = b;
2962
+ }
2963
+ break;
2964
+ case '"':
2965
+ quote_open = !quote_open;
2966
+ *nsp++ = b;
2967
+ break;
2968
+ case '(':
2969
+ if (!quote_open) {
2970
+ br_cnt++;
2971
+ }
2972
+ else {
2973
+ *nsp++ = '\\';
2974
+ }
2975
+ *nsp++ = b;
2976
+ break;
2977
+ case ')':
2978
+ if (!quote_open) {
2979
+ if (br_cnt == 0) {
2980
+ str_insert_char(new_str, (int)(nsp - new_str), '(');
2981
+ nsp++;
2982
+ }
2983
+ else {
2984
+ br_cnt--;
2985
+ }
2986
+ }
2987
+ else {
2988
+ *nsp++ = '\\';
2989
+ }
2990
+ *nsp++ = b;
2991
+ break;
2992
+ case '>':
2993
+ if (quote_open) {
2994
+ if (pb == '<') {
2995
+ /* remove the escape character */
2996
+ nsp--;
2997
+ nsp[-1] = '<';
2998
+ }
2999
+ else {
3000
+ *nsp++ = '\\';
3001
+ }
3002
+ }
3003
+ *nsp++ = b;
3004
+ break;
3005
+ default:
3006
+ if (quote_open) {
3007
+ if (strrchr(special_char, b) && b != '|') {
3008
+ *nsp++ = '\\';
3009
+ }
3010
+ }
3011
+ *nsp++ = b;
3012
+ }
3013
+ pb = b;
3014
+ }
3015
+ if (quote_open) {
3016
+ *nsp++ = '"';
3017
+ }
3018
+ for (;br_cnt > 0; br_cnt--) {
3019
+ *nsp++ = ')';
3020
+ }
3021
+ *nsp = '\0';
3022
+ return new_str;
3023
+ }
3024
+
3025
+ /**
3026
+ * Takes a string and finds whatever tokens it can using the QueryParser's
3027
+ * analyzer. It then turns these tokens (if any) into a boolean query. If it
3028
+ * fails to find any tokens, this method will return NULL.
3029
+ */
3030
+ static FrtQuery *qp_get_bad_query(FrtQParser *qp, char *str)
3031
+ {
3032
+ FrtQuery *volatile q = NULL;
3033
+ qp->recovering = true;
3034
+ assert(qp->fields_top->next == NULL);
3035
+ FLDS(q, get_term_q(qp, field, str));
3036
+ return q;
3037
+ }
3038
+
3039
+ /**
3040
+ * +qp_parse+ takes a string and turns it into a Query object using Ferret's
3041
+ * query language. It must either raise an error or return a query object. It
3042
+ * must not return NULL. If the yacc parser fails it will use a very basic
3043
+ * boolean query parser which takes whatever tokens it can find in the query
3044
+ * and turns them into a boolean query on the default fields.
3045
+ */
3046
+
3047
+ FrtQuery *qp_parse(FrtQParser *self, char *qstr)
3048
+ {
3049
+ FrtQuery *result = NULL;
3050
+ frt_mutex_lock(&self->mutex);
3051
+ /* if qp->fields_top->next is not NULL we have a left over field-stack
3052
+ * object that was not popped during the last query parse */
3053
+ assert(NULL == self->fields_top->next);
3054
+
3055
+ self->recovering = self->destruct = false;
3056
+ if (self->clean_str) {
3057
+ self->qstrp = self->qstr = frt_qp_clean_str(qstr);
3058
+ }
3059
+ else {
3060
+ self->qstrp = self->qstr = qstr;
3061
+ }
3062
+ self->fields = self->def_fields;
3063
+ self->result = NULL;
3064
+ if (0 == yyparse(self)) {
3065
+ result = self->result;
3066
+ }
3067
+
3068
+ if (!result && self->handle_parse_errors) {
3069
+ self->destruct = false;
3070
+ result = qp_get_bad_query(self, self->qstr);
3071
+ }
3072
+ if (self->destruct && !self->handle_parse_errors) {
3073
+ FRT_RAISE(FRT_PARSE_ERROR, frt_xmsg_buffer);
3074
+ }
3075
+ if (!result) {
3076
+ result = frt_bq_new(false);
3077
+ }
3078
+ if (self->clean_str) {
3079
+ free(self->qstr);
3080
+ }
3081
+ frt_mutex_unlock(&self->mutex);
3082
+ return result;
3083
+ }
3084
+