File Coverage

lib/DDC/PP/yyqparser.yp
Criterion Covered Total %
statement 189 414 45.6
branch 4 10 40.0
condition 0 2 0.0
subroutine 128 318 40.2
pod 3 12 25.0
total 324 756 42.8


line stmt bran cond sub pod time code
1             ## -*- Mode: CPerl -*-
2              
3             ################################################################
4             ##
5             ## File: DDC::yyqparser.yp
6             ## Author: Bryan Jurish
7             ##
8             ## Description: Yapp parser specification for DDC queries
9             ## + last updated for ddc v2.2.8
10             ##
11             ################################################################
12              
13             ################################################################
14             ## Header section
15             ################################################################
16             %{
17              
18             ################################################################
19             ##
20             ## File: DDC::yyqparser.yp
21             ## Author: Bryan Jurish
22             ##
23             ## Description: Yapp parser for DDC queries
24             ##
25             ################################################################
26              
27             ##==============================================================
28             ##
29             ## * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING *
30             ##
31             ##==============================================================
32             ##
33             ## Do *NOT* change yyqparser.pm directly, change yyqparser.yp
34             ## and re-call 'yapp' instead!
35             ##
36             ##==============================================================
37              
38             package DDC::PP::yyqparser;
39 20     20   187 use DDC::Utils qw(:escape);
  20         45  
  20         2361  
40 20     20   139 use DDC::PP::Constants;
  20         38  
  20         413  
41 20     20   94 use DDC::PP::CQuery;
  20         41  
  20         365  
42 20     20   95 use DDC::PP::CQCount;
  20         33  
  20         409  
43 20     20   109 use DDC::PP::CQFilter;
  20         34  
  20         425  
44 20     20   94 use DDC::PP::CQueryOptions;
  20         37  
  20         278605  
45              
46             ##----------------------------------------
47             ## API: Hints
48              
49             ## undef = $yyqparser->hint($hint_code,$curtok,$curval)
50             ##
51             sub show_hint {
52 0     0 1 0 $_[0]->{USER}{'hint'} = $_[1];
53 0         0 $_[0]->YYCurtok($_[2]);
54 0         0 $_[0]->YYCurval($_[3]);
55 0         0 $_[0]->YYError;
56             }
57              
58             %}
59              
60             ##----------------------------------------
61 15     15 1 46 ## Grammar: Start symbol
62 15 50       61 %start query
63              
64             ##----------------------------------------
65             ## Grammar: Precedence
66              
67             %nonassoc OP_CLAUSE_MATCHID
68             %nonassoc OP_CLAUSE_CONCAT
69             %nonassoc OP_CLAUSE_BOOL
70             %nonassoc OP_CLAUSE_BASIC
71              
72             #%nonassoc OP_CLAUSE
73             %nonassoc OP_PHRASE
74             %nonassoc OP_WORD
75              
76             %left OP_BOOL_AND OP_BOOL_OR
77             %nonassoc '!'
78              
79             %nonassoc COUNT
80             %nonassoc KEYS
81             %nonassoc NEAR
82             %left ','
83             %left WITH WITHOUT WITHOR
84             %left '='
85             %nonassoc '<'
86             %nonassoc '$'
87             %nonassoc '@' '^' '%' '#' '/' '~'
88              
89             # %left SIM_PRECISE //-- what was this for?
90              
91              
92             ##----------------------------------------
93             ## expect some shift/reduce conflicts:
94             ##---------------------------------------
95             #%expect 3
96              
97             %%
98             ################################################################
99             ## Rules Section
100             ################################################################
101              
102             ##-------------------------------------------------------------
103             ## query (q*): Top Level (Query Root)
104             query:
105 183     183   6494 query_conditions q_directives { $_[0]->SetQuery($_[1]) }
106 28     28   1104 | count_query q_directives { $_[0]->SetQuery($_[1]) }
107             ;
108              
109             ##-------------------------------------------------------------
110             ## count_query (count_*)
111              
112             count_query:
113 28     28   846 COUNT '(' query_conditions count_filters ')' count_filters { $_[0]->newCountQuery($_[3], {%{$_[4]}, %{$_[6]}}) }
  28         59  
  28         151  
114             ;
115              
116             ##-- count_filters: HASH-ref
117             count_filters:
118 56     56   2256 { {} } ##-- empty
119 40     40   1349 | count_filters count_filter { my $tmp={%{$_[1]}, %{$_[2]}}; $tmp }
  40         91  
  40         120  
  40         106  
120             ;
121              
122             ##-- count_filter: HASH-ref
123             count_filter:
124 28     28   944 count_by { $_[1] }
125 2     2   71 | count_sample { $_[1] }
126 0     0   0 | count_limit { $_[1] }
127 4     4   180 | count_sort { $_[1] }
128 6     6   215 | q_comment { {} }
129             ;
130              
131             count_by:
132 0     0   0 BY l_countkeys { {Keys=>$_[2]} }
133 28     28   1609 | BY '[' l_countkeys ']' { {Keys=>$_[3]} }
134             ;
135              
136             count_sample:
137 0     0   0 SAMPLE integer { {Sample=>$_[2]} }
138 2     2   88 | SAMPLE '[' integer ']' { {Sample=>$_[3]} }
139             ;
140              
141             ##-- non-cqcount option
142             count_limit:
143 0     0   0 CLIMIT integer { {Limit=>$_[2]} }
144 0     0   0 | CLIMIT '[' integer ']' { {Limit=>$_[3]} }
145             ;
146              
147             count_sort:
148 4     4   197 count_sort_op count_sort_minmax { $_[2]->{Sort}=$_[1]; $_[2] }
  4         182  
149             ;
150              
151             count_sort_op:
152 2     2   80 LESS_BY_KEY { DDC::PP::LessByCountKey }
153 0     0   0 | GREATER_BY_KEY { DDC::PP::GreaterByCountKey }
154 0     0   0 | LESS_BY_COUNT { DDC::PP::LessByCountValue }
155 2     2   79 | GREATER_BY_COUNT { DDC::PP::GreaterByCountValue }
156             ;
157              
158             count_sort_minmax:
159 4     4   72 { {} } ##-- empty
160 0     0   0 | '[' ']' { {} }
161 0     0   0 | '[' ',' ']' { {} }
162 0     0   0 | '[' symbol ']' { {Lo=>$_[2]} }
163 0     0   0 | '[' symbol ',' ']' { {Lo=>$_[2]} }
164 0     0   0 | '[' ',' symbol ']' { {Hi=>$_[3]} }
165 0     0   0 | '[' symbol ',' symbol ']' { {Lo=>$_[2],Hi=>$_[4]} }
166             ;
167              
168             ##-------------------------------------------------------------
169             ## query_conditions (q*)
170              
171             query_conditions:
172 211     211   7014 q_clause q_filters { $_[1] }
173             ;
174              
175             ##-------------------------------------------------------------
176             ## q_filters (qf*): Filters and Global Query Flags
177             q_filters:
178 211     211   6579 { undef }
179 11     11   414 | q_filters q_comment { undef }
180 7     7   288 | q_filters q_flag { undef }
181 20     20   667 | q_filters q_filter { undef }
182             ;
183              
184             q_comment:
185 15     15   551 KW_COMMENT symbol { push(@{$_[0]->qopts->{Comments}}, $_[2]); undef }
  15         44  
  15         30  
186 2     2   90 | KW_COMMENT '[' symbol ']' { push(@{$_[0]->qopts->{Comments}}, $_[3]); undef }
  2         9  
  2         9  
187             ;
188              
189             q_flag:
190 2     2   75 CNTXT integer { $_[0]->qopts->{ContextSentencesCount} = $_[2]; undef }
  2         7  
191 0     0   0 | CNTXT '[' integer ']' { $_[0]->qopts->{ContextSentencesCount} = $_[3]; undef }
  0         0  
192 2     2   71 | WITHIN s_breakname { push(@{$_[0]->qopts->{Within}}, $_[2]); undef }
  2         6  
  2         4  
193 3     3   128 | SEPARATE_HITS { $_[0]->qopts->{SeparateHits} = 1; undef }
  3         6  
194 0     0   0 | NOSEPARATE_HITS { $_[0]->qopts->{SeparateHits} = 0; undef }
  0         0  
195 0     0   0 | FILENAMES_ONLY { $_[0]->qopts->{EnableBibliography} = 0; undef }
  0         0  
196 0     0   0 | '!' FILENAMES_ONLY { $_[0]->qopts->{EnableBibliography} = 1; undef }
  0         0  
197 0     0   0 | DEBUG_RANK { $_[0]->qopts->{DebugRank} = 1; undef }
  0         0  
198 0     0   0 | '!' DEBUG_RANK { $_[0]->qopts->{DebugRank} = 0; undef }
  0         0  
199             ;
200              
201              
202             q_filter:
203 2     2   84 qf_has_field { $_[1]; }
204 0     0   0 | qf_rank_sort { $_[1]; }
205 0     0   0 | qf_context_sort { $_[1]; }
206 0     0   0 | qf_size_sort { $_[1]; }
207 14     14   535 | qf_date_sort { $_[1]; }
208 0     0   0 | qf_bibl_sort { $_[1]; }
209 0     0   0 | qf_random_sort { $_[1]; }
210 4     4   160 | qf_prune_sort { $_[1]; }
211             ;
212              
213             qf_has_field:
214 2     2   111 HAS_FIELD '[' s_biblname ',' symbol ']' { $_[0]->newf('CQFHasFieldValue', $_[3], $_[5]) }
215 0     0   0 | HAS_FIELD '[' s_biblname ',' regex ']' { $_[0]->newf('CQFHasFieldRegex', $_[3], $_[5]) }
216 0     0   0 | HAS_FIELD '[' s_biblname ',' neg_regex ']' { (my $f=$_[0]->newf('CQFHasFieldRegex', $_[3], $_[5]))->Negate(); $f }
  0         0  
217 0     0   0 | HAS_FIELD '[' s_biblname ',' s_prefix ']' { $_[0]->newf('CQFHasFieldPrefix', $_[3],$_[5]) }
218 0     0   0 | HAS_FIELD '[' s_biblname ',' s_suffix ']' { $_[0]->newf('CQFHasFieldSuffix', $_[3],$_[5]) }
219 0     0   0 | HAS_FIELD '[' s_biblname ',' s_infix ']' { $_[0]->newf('CQFHasFieldInfix', $_[3],$_[5]) }
220 0     0   0 | HAS_FIELD '[' s_biblname ',' '{' l_set '}' ']' { $_[0]->newf('CQFHasFieldSet', $_[3], $_[6]) }
221 0     0   0 | '!' qf_has_field { $_[2]->Negate; $_[2] }
  0         0  
222             ;
223              
224             qf_rank_sort:
225 0     0   0 GREATER_BY_RANK { $_[0]->newf('CQFRankSort', DDC::PP::GreaterByRank) }
226 0     0   0 | LESS_BY_RANK { $_[0]->newf('CQFRankSort', DDC::PP::LessByRank) }
227             ;
228              
229             qf_context_sort:
230 0     0   0 LESS_BY_LEFT qfb_ctxsort { $_[0]->newCFilter(DDC::PP::LessByLeftContext, -1, $_[2]) }
231 0     0   0 | GREATER_BY_LEFT qfb_ctxsort { $_[0]->newCFilter(DDC::PP::GreaterByLeftContext, -1, $_[2]) }
232 0     0   0 | LESS_BY_RIGHT qfb_ctxsort { $_[0]->newCFilter(DDC::PP::LessByRightContext, 1, $_[2]) }
233 0     0   0 | GREATER_BY_RIGHT qfb_ctxsort { $_[0]->newCFilter(DDC::PP::GreaterByRightContext, 1, $_[2]) }
234 0     0   0 | LESS_BY_MIDDLE qfb_ctxsort { $_[0]->newCFilter(DDC::PP::LessByMiddleContext, 0, $_[2]) }
235 0     0   0 | GREATER_BY_MIDDLE qfb_ctxsort { $_[0]->newCFilter(DDC::PP::GreaterByMiddleContext, 0, $_[2]) }
236             ;
237              
238             qf_size_sort:
239 0     0   0 LESS_BY_SIZE qfb_int { $_[0]->newf('CQFSizeSort', DDC::PP::LessBySize, @{$_[2]}) }
  0         0  
240 0     0   0 | GREATER_BY_SIZE qfb_int { $_[0]->newf('CQFSizeSort', DDC::PP::GreaterBySize, @{$_[2]}) }
  0         0  
241 0     0   0 | IS_SIZE '[' int_str ']' { $_[0]->newf('CQFSizeSort', DDC::PP::LessBySize, $_[3],$_[3]) }
242             ;
243              
244             qf_date_sort:
245 10     10   385 LESS_BY_DATE qfb_date { $_[0]->newf('CQFDateSort', DDC::PP::LessByDate, @{$_[2]}) }
  10         37  
246 0     0   0 | GREATER_BY_DATE qfb_date { $_[0]->newf('CQFDateSort', DDC::PP::GreaterByDate, @{$_[2]}) }
  0         0  
247 4     4   186 | IS_DATE '[' date ']' { $_[0]->newf('CQFDateSort', DDC::PP::LessByDate, $_[3],$_[3]) }
248             ;
249              
250             qf_random_sort:
251 0     0   0 RANDOM { $_[0]->newf('CQFRandomSort') }
252 0     0   0 | RANDOM '[' ']' { $_[0]->newf('CQFRandomSort') }
253 0     0   0 | RANDOM '[' int_str ']' { $_[0]->newf('CQFRandomSort',$_[3]) }
254             ;
255              
256             qf_bibl_sort:
257 0     0   0 LESS_BY '[' KW_DATE qfb_bibl ']' { $_[0]->newf('CQFDateSort', DDC::PP::LessByDate, @{$_[4]}) }
  0         0  
258 0     0   0 | GREATER_BY '[' KW_DATE qfb_bibl ']' { $_[0]->newf('CQFDateSort', DDC::PP::GreaterByDate, @{$_[4]}) }
  0         0  
259 0     0   0 | LESS_BY '[' s_biblname qfb_bibl ']' { $_[0]->newf('CQFBiblSort', DDC::PP::LessByFreeBiblField, $_[3], @{$_[4]}) }
  0         0  
260 0     0   0 | GREATER_BY '[' s_biblname qfb_bibl ']' { $_[0]->newf('CQFBiblSort', DDC::PP::LessByFreeBiblField, $_[3], @{$_[4]}) }
  0         0  
261             ;
262              
263             qf_prune_sort:
264 4     4   243 PRUNE_ASC '[' int_str l_prunekeys ']' { $_[0]->newf('CQFPrune', DDC::PP::LessByPruneKey, $_[3], $_[4]); }
265 0     0   0 | PRUNE_DESC '[' int_str l_prunekeys ']' { $_[0]->newf('CQFPrune', DDC::PP::GreaterByPruneKey, $_[3], $_[4]); }
266             ;
267              
268             ##-------------------------------------------------------------
269             ## (qfb*): Filter Bounds
270              
271             ##-- qfb_int: [0:$lb,1:$ub]
272             qfb_int:
273 0     0   0 { [] } ##-- empty
274 0     0   0 | '[' ']' { [] }
275 0     0   0 | '[' ',' ']' { [] }
276 0     0   0 | '[' int_str ']' { [$_[2]] }
277 0     0   0 | '[' int_str ',' ']' { [$_[2]] }
278 0     0   0 | '[' int_str ',' int_str ']' { [$_[2],$_[4]] }
279 0     0   0 | '[' ',' int_str ']' { [undef,$_[3]] }
280             ;
281              
282             ##-- qfb_date: [0:$lb,1:$ub]
283             qfb_date:
284 2     2   42 { [] } ##-- empty
285 0     0   0 | '[' ']' { [] }
286 0     0   0 | '[' date ']' { [$_[2]] }
287 0     0   0 | '[' date ',' ']' { [$_[2]] }
288 8     8   376 | '[' date ',' date ']' { [$_[2],$_[4]] }
289 0     0   0 | '[' ',' date ']' { [undef,$_[3]] }
290             ;
291              
292             ##-- qfb_bibl: [0:$lb,1:$ub]
293             qfb_bibl:
294 0     0   0 { [] } ##-- empty
295 0     0   0 | qfb_bibl_ne { $_[1] }
296             ;
297              
298              
299             ##-- qfb_bibl_ne: [0:$lb,1:$ub]
300             qfb_bibl_ne:
301 0     0   0 ',' { [] }
302 0     0   0 | ',' ',' { [] }
303 0     0   0 | ',' symbol { [$_[2]] }
304 0     0   0 | ',' symbol ',' { [$_[2]] }
305 0     0   0 | ',' ',' symbol { [undef,$_[3]] }
306 0     0   0 | ',' symbol ',' symbol { [$_[2],$_[4]] }
307             ;
308              
309             ##-- qfb_ctxsort : [0:$field,1:$matchid,2:$offset,3:$lb,4:$ub]
310             qfb_ctxsort:
311 0     0   0 { [] } ##-- empty
312 0     0   0 | '[' qfb_ctxkey ']' { $_[2] }
313 0     0   0 | '[' qfb_ctxkey qfb_bibl_ne ']' { [@{$_[2]}, @{$_[3]}] }
  0         0  
  0         0  
314             ;
315              
316             ##-- qfb_ctxkey: [0:$field,1:$matchid,2:$offset]
317             qfb_ctxkey:
318 0     0   0 sym_str qfbc_matchref qfbc_offset { [$_[1],$_[2],$_[3]] }
319 0     0   0 | qfbc_matchref qfbc_offset { [undef,$_[1],$_[2]] }
320             ;
321              
322             ##-- qfbc_matchref: $matchid
323             qfbc_matchref:
324 0     0   0 { 0 } ##-- empty
325 0     0   0 | matchid { $_[1] }
326             ;
327              
328             ##-- qfbc_offset: offset
329             qfbc_offset:
330 0     0   0 { undef } ##-- empty: use filter-type default
331 0     0   0 | integer { $_[1] }
332 0     0   0 | '+' integer { $_[2] }
333 0     0   0 | '-' integer { -$_[2] }
334             ;
335              
336              
337             ##-------------------------------------------------------------
338             ## q_directives: global server directives
339              
340             q_directives:
341 211     211   6545 { undef } ##-- empty: ignore
342 34     34   1186 | q_directives qd_subcorpora { undef }
343             ;
344              
345             qd_subcorpora:
346 34     34   1932 ':' { @{$_[0]->qopts->{Subcorpora}}=qw(); } l_subcorpora { undef }
  34         89  
  34         908  
347             ;
348              
349              
350             ##-------------------------------------------------------------
351             ## q_clause (qc*): query clauses (logical operations)
352              
353             q_clause:
354 224     224   7429 qc_basic %prec OP_CLAUSE_BASIC { $_[1] }
355 23     23   823 | qc_boolean %prec OP_CLAUSE_BOOL { $_[1] }
356 10     10   358 | qc_concat %prec OP_CLAUSE_CONCAT { $_[1] }
357 0     0   0 | qc_matchid %prec OP_CLAUSE_MATCHID { $_[1] }
358             ;
359              
360             qc_matchid:
361 0     0   0 q_clause matchid { $_[1]->SetMatchId($_[2]); $_[1] }
  0         0  
362 0     0   0 | '(' qc_matchid ')' { $_[2] }
363             ;
364              
365              
366             ##-------------------------------------------------------------
367             ## qc_boolean: query clause: complex boolean expression
368             qc_boolean:
369 21     21   848 q_clause OP_BOOL_AND q_clause { $_[0]->newq('CQAnd', $_[1],$_[3]) }
370 2     2   76 | q_clause OP_BOOL_OR q_clause { $_[0]->newq('CQOr', $_[1],$_[3]) }
371 0     0   0 | '!' q_clause { $_[2]->Negate; $_[2] }
  0         0  
372 0     0   0 | '(' qc_boolean ')' { $_[2] }
373             ;
374              
375             ##-------------------------------------------------------------
376             ## qc_concat: query clause: implicit logical conjunction
377             qc_concat:
378 10     10   364 qc_basic qc_basic { $_[0]->newq('CQAndImplicit', $_[1],$_[2]) }
379 0     0   0 | qc_concat qc_basic { $_[0]->newq('CQAndImplicit', $_[1],$_[2]) }
380 2     2   110 | '(' qc_concat ')' { $_[2] }
381             ;
382              
383              
384             ##-------------------------------------------------------------
385             ## qc_basic: query clause: basic (single logical condition)
386              
387             qc_basic:
388 244     244   8368 qc_tokens %prec OP_PHRASE { $_[1] }
389 0     0   0 | qc_near %prec OP_PHRASE { $_[1] }
390             ;
391              
392             qc_near:
393 0     0   0 NEAR '(' qc_tokens ',' qc_tokens ',' integer ')' { $_[0]->newq('CQNear', $_[7],$_[3],$_[5]) }
394 0     0   0 | NEAR '(' qc_tokens ',' qc_tokens ',' qc_tokens ',' integer ')' { $_[0]->newq('CQNear', $_[9],$_[3],$_[5],$_[7]) }
395 0     0   0 | qc_near matchid { $_[1]->SetMatchId($_[2]); $_[1] }
  0         0  
396 0     0   0 | '(' qc_near ')' { $_[2] }
397             ;
398              
399              
400             ##-------------------------------------------------------------
401             ## qc_tokens: condition with hit position (can be arg to NEAR()):
402              
403             qc_tokens:
404 242     242   8032 qc_word %prec OP_WORD { $_[1] }
405 2     2   66 | qc_phrase %prec OP_PHRASE { $_[1] }
406 0     0   0 | qc_tokens matchid %prec OP_PHRASE { $_[1]->SetMatchId($_[2]); $_[1] }
  0         0  
407             ;
408              
409             qc_phrase:
410 2     2   109 '"' l_phrase '"' { $_[2] }
411 0     0   0 | '(' qc_phrase ')' { $_[2] }
412             ;
413              
414              
415             ##-------------------------------------------------------------
416             ## qc_word (qw*): Single-Token Queries
417              
418             qc_word:
419 231     231   8676 qw_bareword { $_[1] }
420 4     4   220 | qw_exact { $_[1] }
421 11     11   412 | qw_regex { $_[1] }
422 0     0   0 | qw_any { $_[1] }
423 0     0   0 | qw_set_infl { $_[1] }
424 4     4   148 | qw_set_exact { $_[1] }
425 0     0   0 | qw_infix { $_[1] }
426 0     0   0 | qw_infix_set { $_[1] }
427 4     4   148 | qw_prefix { $_[1] }
428 0     0   0 | qw_prefix_set { $_[1] }
429 0     0   0 | qw_suffix { $_[1] }
430 0     0   0 | qw_suffix_set { $_[1] }
431 0     0   0 | qw_thesaurus { $_[1] }
432 0     0   0 | qw_morph { $_[1] }
433 0     0   0 | qw_lemma { $_[1] }
434 0     0   0 | qw_chunk { $_[1] }
435 0     0   0 | qw_anchor { $_[1] }
436 0     0   0 | qw_listfile { $_[1] }
437 2     2   78 | qw_with { $_[1] }
438 2     2   90 | qw_without { $_[1] }
439 2     2   79 | qw_withor { $_[1] }
440 0     0   0 | qw_keys { $_[1] }
441 30     30   1017 | qw_matchid { $_[1] }
442 4     4   211 | '(' qc_word ')' { $_[2] }
443             ;
444              
445             qw_bareword:
446 225     225   6513 s_word l_txchain { $_[0]->newq('CQTokInfl', "", $_[1], $_[2]) }
447 6     6   181 | s_index '=' s_word l_txchain { $_[0]->newq('CQTokInfl', $_[1], $_[3], $_[4]) }
448             ;
449              
450             qw_exact:
451 4     4   245 '@' s_word { $_[0]->newq('CQTokExact', "", $_[2]) }
452 0     0   0 | s_index '=' '@' s_word { $_[0]->newq('CQTokExact', $_[1], $_[4]) }
453             ;
454              
455             qw_regex:
456 11     11   788 regex { $_[0]->newq('CQTokRegex', "", $_[1]) }
457 0     0   0 | s_index '=' regex { $_[0]->newq('CQTokRegex', $_[1],$_[3]) }
458 0     0   0 | neg_regex { $_[0]->newq('CQTokRegex', "", $_[1], 1) }
459 0     0   0 | s_index '=' neg_regex { $_[0]->newq('CQTokRegex', $_[1], $_[3], 1) }
460             ;
461              
462             qw_any:
463 0     0   0 '*' { $_[0]->newq('CQTokAny') }
464 0     0   0 | s_index '=' '*' { $_[0]->newq('CQTokAny',$_[1]) }
465             ;
466              
467             qw_set_exact:
468 4     4   166 AT_LBRACE l_set '}' { $_[0]->newq('CQTokSet', "", undef, $_[2]) }
469 0     0   0 | s_index '=' AT_LBRACE l_set '}' { $_[0]->newq('CQTokSet', $_[1], undef, $_[2]) }
470             ;
471              
472             qw_set_infl:
473 0     0   0 '{' l_set '}' l_txchain { $_[0]->newq('CQTokSetInfl', "", $_[2], $_[4]) }
474 0     0   0 | s_index '=' '{' l_set '}' l_txchain { $_[0]->newq('CQTokSetInfl', $_[1], $_[4], $_[6]) }
475             ;
476              
477             qw_prefix:
478 4     4   160 s_prefix { $_[0]->newq('CQTokPrefix', "", $_[1]) }
479 0     0   0 | s_index '=' s_prefix { $_[0]->newq('CQTokPrefix', $_[1], $_[3]) }
480             ;
481              
482             qw_suffix:
483 0     0   0 s_suffix { $_[0]->newq('CQTokSuffix', "", $_[1]) }
484 0     0   0 | s_index '=' s_suffix { $_[0]->newq('CQTokSuffix', $_[1], $_[3]) }
485             ;
486              
487             qw_infix:
488 0     0   0 s_infix { $_[0]->newq('CQTokInfix', "", $_[1]) }
489 0     0   0 | s_index '=' s_infix { $_[0]->newq('CQTokInfix', $_[1], $_[3]) }
490             ;
491              
492             qw_infix_set:
493 0     0   0 STAR_LBRACE l_set RBRACE_STAR { $_[0]->newq('CQTokInfixSet', "", $_[2]) }
494 0     0   0 | s_index '=' STAR_LBRACE l_set RBRACE_STAR { $_[0]->newq('CQTokInfixSet', $_[1], $_[4]) }
495             ;
496              
497             qw_prefix_set:
498 0     0   0 '{' l_set RBRACE_STAR { $_[0]->newq('CQTokPrefixSet',"", $_[2]) }
499 0     0   0 | s_index '=' '{' l_set RBRACE_STAR { $_[0]->newq('CQTokPrefixSet',$_[1], $_[4]) }
500             ;
501              
502             qw_suffix_set:
503 0     0   0 STAR_LBRACE l_set '}' { $_[0]->newq('CQTokSuffixSet',"", $_[2]) }
504 0     0   0 | s_index '=' STAR_LBRACE l_set '}' { $_[0]->newq('CQTokSuffixSet',$_[1], $_[4]) }
505             ;
506              
507             qw_thesaurus:
508 0     0   0 COLON_LBRACE s_semclass '}' { $_[0]->newq('CQTokThes', "Thes",$_[2]) }
509 0     0   0 | s_index '=' ':' '{' s_semclass '}' { $_[0]->newq('CQTokThes', $_[1], $_[5]) }
510             ;
511              
512             qw_morph:
513 0     0   0 '[' l_morph ']' { $_[0]->newq('CQTokMorph', "MorphPattern", $_[2]) }
514 0     0   0 | s_index '=' '[' l_morph ']' { $_[0]->newq('CQTokMorph', $_[1], $_[4]) }
515             ;
516              
517             qw_lemma:
518 0     0   0 '%' s_lemma { $_[0]->newq('CQTokLemma', "Lemma", $_[2]) }
519 0     0   0 | s_index '=' '%' s_lemma { $_[0]->newq('CQTokLemma', $_[1], $_[4]) }
520             ;
521              
522             qw_chunk:
523 0     0   0 '^' s_chunk { $_[0]->newq('CQTokChunk', "", $_[2]) }
524 0     0   0 | s_index '=' '^' s_chunk { $_[0]->newq('CQTokChunk', $_[1], $_[4]) }
525             ;
526              
527             qw_anchor:
528 0     0   0 DOLLAR_DOT '=' int_str { $_[0]->newq('CQTokAnchor', "", $_[3]) }
529 0     0   0 | DOLLAR_DOT symbol '=' int_str { $_[0]->newq('CQTokAnchor', $_[2], $_[4]) }
530             ;
531              
532             qw_listfile:
533 0     0   0 '<' s_filename { $_[0]->newq('CQTokFile', "", $_[2]) }
534 0     0   0 | s_index '=' '<' s_filename { $_[0]->newq('CQTokFile', $_[1], $_[4]) }
535             ;
536              
537             qw_with:
538 2     2   86 qc_word WITH qc_word { $_[0]->newq('CQWith', $_[1],$_[3]) }
539             ;
540              
541             qw_without:
542 2     2   81 qc_word WITHOUT qc_word { $_[0]->newq('CQWithout', $_[1],$_[3]) }
543             ;
544              
545             qw_withor:
546 2     2   83 qc_word WITHOR qc_word { $_[0]->newq('CQWithor', $_[1],$_[3]) }
547             ;
548              
549             qw_keys:
550 0     0   0 KEYS '(' qwk_countsrc ')' { $_[0]->newKeysQuery($_[3][0], $_[3][1]); }
551 0     0   0 | qwk_indextuple '=' KEYS '(' qwk_countsrc ')' { $_[0]->newKeysQuery($_[5][0], $_[5][1], $_[1]); }
552             ;
553              
554             qwk_indextuple:
555 0     0   0 '$' '(' l_indextuple ')' { $_[3] }
556             ;
557              
558             ##-- qwk_countsrc: [$qCount, \%keysOpts]
559             qwk_countsrc:
560 0     0   0 count_query { [$_[1], {}] }
561 0     0   0 | query_conditions count_filters { [$_[0]->newCountQuery($_[1], $_[2]), $_[2]] }
562             ;
563              
564             qw_matchid:
565 30     30   1101 qc_word matchid { $_[1]->SetMatchId($_[2]); $_[1] }
  30         53  
566             ;
567              
568              
569             ##-------------------------------------------------------------
570             ## l_*: List-like constituents
571              
572             l_set:
573 4     4   146 { [] } ##-- empty
574 8     8   262 | l_set s_word { push(@{$_[1]}, $_[2]); $_[1] }
  8         19  
  8         17  
575 4     4   156 | l_set ',' { $_[1] }
576             # | l_set ';' { $_[1] }
577             ;
578              
579             l_morph:
580 0     0   0 { [] } ##-- empty
581 0     0   0 | l_morph s_morphitem { push(@{$_[1]}, $_[2]); $_[1] }
  0         0  
  0         0  
582 0     0   0 | l_morph ',' { $_[1] }
583 0     0   0 | l_morph ';' { $_[1] } ##-- backwards-compatible
584             ;
585              
586             l_phrase :
587 2     2   55 qc_word { $_[0]->newq('CQSeq', [$_[1]]) }
588 0     0   0 | l_phrase qc_word { $_[1]->Append($_[2]); $_[1] }
  0         0  
589 2     2   67 | l_phrase '#' integer qc_word { $_[1]->Append($_[4], $_[3]); $_[1] }
  2         5  
590 0     0   0 | l_phrase HASH_LESS integer qc_word { $_[1]->Append($_[4], $_[3], '<'); $_[1] }
  0         0  
591 0     0   0 | l_phrase HASH_GREATER integer qc_word { $_[1]->Append($_[4], $_[3], '>'); $_[1] }
  0         0  
592 2     2   62 | l_phrase HASH_EQUAL integer qc_word { $_[1]->Append($_[4], $_[3], '='); $_[1] }
  2         4  
593             ;
594              
595             l_txchain:
596 231     231   7058 { []; } ##-- empty
597 4     4   142 | l_txchain s_expander { push(@{$_[1]}, $_[2]); $_[1] }
  4         12  
  4         9  
598             ;
599              
600             ##-- l_countkeys: CQCountKeyExprList
601             l_countkeys:
602 0     0   0 { $_[0]->newq('CQCountKeyExprList') }
603 28     28   747 | count_key { $_[0]->newq('CQCountKeyExprList', Exprs=>[$_[1]]) }
604 2     2   60 | l_countkeys ',' count_key { $_[1]->PushKey($_[3]); $_[1] }
  2         5  
605             ;
606              
607             ##-- l_prunekeys: CQCountKeyExprList
608             l_prunekeys:
609 4     4   97 { $_[0]->newq('CQCountKeyExprList') }
610 0     0   0 | prune_key { $_[0]->newq('CQCountKeyExprList', Exprs=>[$_[1]]) }
611 4     4   134 | l_prunekeys ',' prune_key { $_[1]->PushKey($_[3]); $_[1] }
  4         10  
612             ;
613              
614             l_indextuple:
615 0     0   0 { [] }
616 0     0   0 | s_indextuple_item { [$_[1]] }
617 0     0   0 | l_indextuple ',' s_indextuple_item { push(@{$_[1]},$_[3]); $_[1] }
  0         0  
  0         0  
618             ;
619              
620             l_subcorpora:
621 2     2   44 { undef } ##-- empty
622 32     32   1209 | s_subcorpus { push(@{$_[0]->qopts->{Subcorpora}}, $_[1]); undef }
  32         76  
  32         59  
623 18     18   622 | l_subcorpora ',' s_subcorpus { push(@{$_[0]->qopts->{Subcorpora}}, $_[3]); undef }
  18         61  
  18         34  
624             ;
625              
626             ##-------------------------------------------------------------
627             ## count_key, prune_key: count- and prune-key expressions
628              
629             count_key:
630 0     0   0 count_key_const { $_[1] }
631 12     12   432 | count_key_meta { $_[1] }
632 18     18   688 | count_key_token { $_[1] }
633 2     2   76 | count_key '~' replace_regex { $_[0]->newq('CQCountKeyExprRegex', $_[1],@{$_[3]}) }
  2         11  
634 0     0   0 | '(' count_key ')' { $_[2] }
635             ;
636              
637             prune_key:
638 0     0   0 count_key_const { $_[1] }
639 4     4   141 | count_key_meta { $_[1] }
640 0     0   0 | prune_key '~' replace_regex { $_[0]->newq('CQCountKeyExprRegex', $_[1],@{$_[3]}) }
  0         0  
641 0     0   0 | '(' prune_key ')' { $_[2] }
642             ;
643              
644             count_key_const:
645 0     0   0 '*' { $_[0]->newq('CQCountKeyExprConstant', "*") }
646 0     0   0 | '@' symbol { $_[0]->newq('CQCountKeyExprConstant', $_[2]) }
647             ;
648              
649             count_key_meta:
650 0     0   0 KW_FILEID { $_[0]->newq('CQCountKeyExprFileId', $_[1]) }
651 0     0   0 | KW_FILENAME { $_[0]->newq('CQCountKeyExprFileName', $_[1]) }
652 0     0   0 | KW_DATE { $_[0]->newq('CQCountKeyExprDate', $_[1]) }
653 2     2   74 | KW_DATE '/' integer { $_[0]->newq('CQCountKeyExprDateSlice', $_[1],$_[3]) }
654 14     14   554 | s_biblname { $_[0]->newq('CQCountKeyExprBibl', $_[1]) }
655             ;
656              
657             count_key_token:
658 18     18   648 s_index ck_matchid ck_offset { $_[0]->newq('CQCountKeyExprToken', $_[1],$_[2],$_[3]) }
659             ;
660              
661             ck_matchid:
662 8     8   163 { 0 } ##-- empty
663 10     10   333 | matchid { $_[1] }
664             ;
665              
666             ck_offset:
667 2     2   41 { 0 } ##-- empty
668 16     16   522 | integer { $_[1] }
669 0     0   0 | '+' integer { $_[2] }
670 0     0   0 | '-' integer { -$_[2] }
671             ;
672              
673              
674             ##-------------------------------------------------------------
675             ## s_*: semantic sugar for symbols
676              
677             s_index:
678 0     0   0 '$' { '' }
679 24     24   841 | index { $_[1] }
680             ;
681              
682             s_indextuple_item:
683 0     0   0 s_index { $_[1] }
684 0     0   0 | symbol { $_[1] }
685             ;
686              
687 243     243   8848 s_word: symbol { $_[1] } ;
688 0     0   0 s_semclass: symbol { $_[1] } ;
689 0     0   0 s_lemma: symbol { $_[1] } ;
690 0     0   0 s_chunk: symbol { $_[1] } ;
691 0     0   0 s_filename: symbol { $_[1] } ;
692 0     0   0 s_morphitem: symbol { $_[1] } ;
693 50     50   1738 s_subcorpus: symbol { $_[1] } ;
694 16     16   553 s_biblname: symbol { $_[1] } ;
695              
696 0     0   0 s_breakname: symbol { $_[1] }
697 2     2   77 | KW_FILENAME { "file" }
698             ;
699              
700              
701             ##-------------------------------------------------------------
702             ## Preterminals
703              
704             symbol:
705 316     316   13016 SYMBOL { unescape($_[1]) }
706 8     8   326 | INTEGER { $_[1] }
707 4     4   166 | DATE { $_[1] }
708             ;
709              
710             index:
711 0     0   0 '$' { '' }
712 24     24   949 | INDEX { unescape($_[1]) }
713             ;
714              
715 0     0   0 sym_str: SYMBOL { unescape($_[1]) } ;
716              
717 4     4   172 s_prefix: PREFIX { unescape($_[1]) } ;
718 0     0   0 s_suffix: SUFFIX { unescape($_[1]) } ;
719 0     0   0 s_infix: INFIX { unescape($_[1]) } ;
720              
721 4     4   166 s_expander: EXPANDER { unescape($_[1]) } ;
722              
723             regex:
724 11     11   290 REGEX { $_[0]->newre($_[1]) }
725 0     0   0 | REGEX REGOPT { $_[0]->newre($_[1],$_[2]) }
726             ;
727              
728             neg_regex:
729 0     0   0 NEG_REGEX { $_[0]->newre($_[1]) }
730 0     0   0 | NEG_REGEX REGOPT { $_[0]->newre($_[1],$_[2]) }
731             ;
732              
733             ##-- replace_regex: [$pattern,$replacement,$modifiers]
734 2     2   57 replace_regex: REGEX_SEARCH REGEX_REPLACE { [$_[1],$_[2],''] }
735 0     0   0 | REGEX_SEARCH REGEX_REPLACE REGOPT { [$_[1],$_[2],$_[3]] }
736             ;
737              
738 70     70   2851 int_str: INTEGER { $_[1] } ;
739              
740 20     20   250 integer: int_str { no warnings 'numeric'; ($_[1]+0) } ;
  20     66   62  
  20         27716  
  66         2338  
741              
742             date:
743 8     8   300 DATE { $_[1] }
744 12     12   456 | INTEGER { $_[1] }
745             ;
746              
747 40     40   1369 matchid: matchid_eq integer { $_[0]->yybegin('INITIAL'); $_[2] } ;
  40         103  
748              
749 40     40   2029 matchid_eq: '=' { $_[0]->yybegin('Q_MATCHID'); $_[1] } ;
  40         77  
750 15         32027  
751             %%
752             ##############################################################
753 15         2129 # Footer Section
754             ###############################################################
755              
756             package DDC::PP::yyqparser;
757             #require Exporter;
758              
759             ## $q = $yyqparser->newq($querySubclass, @queryArgs)
760             ## + just wraps DDC::PP::CQueryCompiler::newq
761             sub newq {
762 391     391 0 1372 return $_[0]{USER}{qc}->newq(@_[1..$#_]);
763             }
764              
765             ## $qf = $yyqparser->newf($filterSubclass, @filterArgs)
766             ## + wraps DDC::PP::CQueryCompiler::newf and pushes filter onto current options' filter-list
767             sub newf {
768 20     20 0 86 my $f = $_[0]{USER}{qc}->newf(@_[1..$#_]);
769 20         42 push(@{$_[0]->qopts->{Filters}}, $f);
  20         51  
770 20         59 return $f;
771             }
772              
773             ## $cf = $yyqparser->newCFilter($filterSortType, $defaultOffset, \@args)
774             sub newCFilter {
775 0     0 0 0 my ($qp,$type,$off,$args) = @_;
776             #print STDERR "newCFilter: ", Data::Dumper->Dump([@_[1..$#_]]), "\n"; ##-- DEBUG
777 0 0       0 $args->[2] = $off if (!defined($args->[2]));
778 0         0 return $qp->newf('CQFContextSort', $type, @$args);
779             }
780              
781             ## $qc = $yyqparser->newCountQuery($qSrc, \%qcOpts)
782             sub newCountQuery {
783 28     28 0 60 my ($qp,$qsrc,$qcopts) = @_;
784 28         74 $qp->SetQuery($qsrc);
785 28         64 my $qc = $qp->newq('CQCount', $qsrc);
786 28 50       49 foreach my $key (keys %{$qcopts||{}}) {
  28         129  
787 34 50       284 $qc->can("set$key")->($qc, $qcopts->{$key}) if ($qc->can("set$key"));
788             }
789 28         84 return $qc;
790             }
791              
792             ## $qk = $yyqparser->newKeysQuery($qCount, \%qcOpts, $indexTuple)
793             sub newKeysQuery {
794 0     0 0 0 my ($qp,$qcount,$qcopts,$ituple) = @_;
795 0   0     0 return $qp->newq('CQKeys', $qcount, ($qcopts||{})->{Limit}, $ituple);
796             }
797              
798             ## $re = $yyqparser->newre($regex, $regopt)
799             ## + wraps DDC::PP::CQueryCompiler::newre
800             sub newre {
801 11     11 0 50 return $_[0]{USER}{qc}->newre(@_[1..$#_]);
802             }
803              
804             ## $qo = $yyqparser->qopts()
805             ## + just wraps DDC::PP::CQueryCompiler::qopts()
806             sub qopts {
807 606     606 0 1812 return $_[0]{USER}{qc}->qopts(@_[1..$#_])
808             }
809              
810             ## $q = $yyqparser->SetQuery($q)
811             ## + sets compiler query and assigns its options
812             sub SetQuery {
813 239 50   239 0 1060 $_[1]->setOptions($_[0]->qopts) if ($_[1]);
814 239         624 $_[0]->qopts(DDC::PP::CQueryOptions->new);
815 239         723 $_[0]{USER}{qc}->setQuery($_[1]);
816             }
817              
818             ## undef = $yyqparser->yycarp($message_template,\%macros)
819             sub yycarp {
820 0     0 1 0 die($_[0]{USER}{qc}->setError(@_[1..$#_]));
821             }
822              
823             ## undef = $yyqparser->yybegin($q)
824             sub yybegin {
825 80     80 0 200 $_[0]{USER}{qc}{lexer}{state} = $_[1];
826             }
827              
828             ### $esc = $yyqparser->unescape($sym)
829             ### + wraps DDC::Query::Parser::unescape($sym)
830             #sub unescape {
831             # return $_[0]{USER}{qc}->unescape($_[1]);
832             #}
833              
834             1; ##-- be happy
835              
836             __END__