File Coverage

lib/DDC/PP/yyqparser.yp
Criterion Covered Total %
statement 177 395 44.8
branch 4 10 40.0
condition 0 2 0.0
subroutine 119 303 39.2
pod 3 12 25.0
total 303 722 41.9


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