File Coverage

blib/lib/Data/Generate.pm
Criterion Covered Total %
statement 547 570 95.9
branch 123 148 83.1
condition 53 69 76.8
subroutine 55 56 98.2
pod 38 38 100.0
total 816 881 92.6


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             ################################################################################
3             # package Data::Generate
4             # Description: returns an SQL-Data generator object
5             # Design: during parsing we create following data structure internally:
6             # 'value_term': ascii string
7             # 'value_column': array of possible alternative choices for the value term
8             # 'value_chain': a chain of value columns
9             # 'chain_list': the generator itself
10             # output data : output data is retrieved by subsequent concatenation
11             # of value terms in a value chain. If more than one value chains are defined,
12             # then, based on weigthing, each chain at turn will be "asked" to return an
13             # output value, until an array of the requested cardinality is filled.
14             #
15             ################################################################################
16             package Data::Generate;
17            
18              
19 4     4   159104 use 5.006;
  4         16  
  4         550  
20 4     4   26 use strict;
  4         10  
  4         381  
21 4     4   23 use warnings;
  4         11  
  4         152  
22 4     4   21 use Carp;
  4         8  
  4         1201  
23 4     4   13877 use Parse::RecDescent;
  4         273219  
  4         36  
24 4     4   4232 use Date::Parse;
  4         35367  
  4         551  
25 4     4   3474 use Date::DayOfWeek;
  4         11193  
  4         254  
26              
27 4     4   29 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
  4         9  
  4         1854  
28             require Exporter;
29              
30              
31             our @ISA = qw(Exporter);
32              
33              
34              
35              
36             # Items to export into callers namespace by default. Note: do not export
37             # names by default without a very good reason. Use EXPORT_OK instead.
38             # Do not simply export all your public functions/methods/constants.
39              
40             # This allows declaration use Data::Generate ':all';
41             our %EXPORT_TAGS = ( 'all' => [ qw(
42             parse
43             ) ] );
44             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
45             our @EXPORT = qw();
46             our $VERSION = '0.02';
47              
48              
49             $Data::Generate::Parser=undef;
50             $Data::Generate::current=undef;
51             $Data::Generate::ACTUAL_VALUE_COLUMN=undef;
52             $Data::Generate::VC_RANGE_REVERSE_FLAG=undef;
53              
54              
55              
56             #-------------------------------------------------------------------------------
57             # Various constant definitions
58             #-------------------------------------------------------------------------------
59             $Data::Generate::vcol_type ={};
60             $Data::Generate::vcol_type->{year}->{lowlimit}=1970; # Unix 32 bit date
61             $Data::Generate::vcol_type->{year}->{highlimit}=2037; # Unix 32 bit date
62             $Data::Generate::vcol_type->{year}->{type}='year';
63             $Data::Generate::vcol_type->{month}->{lowlimit}=1;
64             $Data::Generate::vcol_type->{month}->{highlimit}=12;
65             $Data::Generate::vcol_type->{month}->{type}='month';
66             $Data::Generate::vcol_type->{day}->{lowlimit}=1;
67             $Data::Generate::vcol_type->{day}->{highlimit}=31;
68             $Data::Generate::vcol_type->{day}->{type}='day';
69             $Data::Generate::vcol_type->{hour}->{lowlimit}=0;
70             $Data::Generate::vcol_type->{hour}->{highlimit}=24;
71             $Data::Generate::vcol_type->{hour}->{type}='hour';
72             $Data::Generate::vcol_type->{minute}->{lowlimit}=0;
73             $Data::Generate::vcol_type->{minute}->{highlimit}=59;
74             $Data::Generate::vcol_type->{minute}->{type}='minute';
75             $Data::Generate::vcol_type->{second}->{lowlimit}=0;
76             $Data::Generate::vcol_type->{second}->{highlimit}=59;
77             $Data::Generate::vcol_type->{second}->{type}='second';
78             $Data::Generate::vcol_type->{fraction}->{type}='fraction';
79              
80             $Data::Generate::vchain_type ={};
81             $Data::Generate::vchain_type->{DATE}->{type}='DATE';
82             $Data::Generate::vchain_type->{DATE}->{vcol_output_format}=
83             ['%s',' %02d:','%02d:','%02d','.%s'];
84             # ['%04d','%02d','%02d',' %02d:','%02d:','%02d','.%s'];
85             $Data::Generate::vchain_type->{DATE}->{check_type}=sub {
86 4     4   26 no warnings "all";
  4         10  
  4         1540  
87             my $input=shift;
88             (my $ss,my $mm, my $hh,my $day,my $month,my $year)= strptime($input);
89             return undef unless defined $year;
90             $year+=1900;
91             $month++;
92             my $precision=0;
93             $precision = $Data::Generate::current->{ct_precision}
94             if defined $Data::Generate::current->{ct_precision};
95             my $result=sprintf('%04d%02d%02d %02d:%02d:%02.'.$precision.'f',
96             $year, $month, $day,$hh,$mm,$ss);
97             return undef unless defined str2time($result);
98             return $result;
99             };
100             $Data::Generate::vchain_type->{DATE}->{output_format_fct}=sub {
101             my $input=shift;
102             return $input unless defined $Data::Generate::current->{ct_precision};
103             my $precision=$Data::Generate::current->{ct_precision};
104             my ( $date_string, $date_fraction) = ($input =~ /^(.+?)(\d{2}\.\d*)$/);
105             $date_fraction=sprintf('%02.'.$precision.'f',$date_fraction);
106             return $date_string.$date_fraction;
107             };
108              
109             $Data::Generate::vchain_type->{DATE}->{subtype}->{'DATEWITHFRACTION'}
110             ->{fraction_start_ix}=4;
111              
112              
113             $Data::Generate::vchain_type->{INTEGER}->{type}='INTEGER';
114             $Data::Generate::vchain_type->{INTEGER}->{check_type}=sub {
115 4     4   210 no warnings "all";
  4         8  
  4         38398  
116             my $input=shift;
117             my $result=int($input);
118             return undef unless $result == $input;
119             return $result;
120             };
121              
122             $Data::Generate::vchain_type->{FLOAT}->{output_format_fct}=sub {
123             my $input=shift;
124             $input =~ s/^\-0+\.0+$/0.0/;
125             $input =~ s/^\+//;
126             return eval($input);
127             };
128              
129             $Data::Generate::vchain_type->{FLOAT}->{check_type}=sub {
130             # no warnings "all";
131             my $input=shift;
132             my $result=$input*1.0;
133             $input=eval($input);
134             $result=eval($result);
135             return undef unless $result == $input;
136             return $result;
137             };
138              
139              
140             $Data::Generate::vcol_type->{weekday}->{type}='weekday';
141             $Data::Generate::vcol_type->{weekday}->{term_list}=[qw{SUN MON TUE WED THU FRI SAT}];
142              
143             ################################################################################
144             # sub new
145             # Description:
146             # inital constructor for a list of value chains.
147             #
148             ################################################################################
149             sub new
150             {
151 29     29 1 65 my ($class,$text) = @_;
152 29         66 my $self = {};
153 29         98 $self->{vchain_text} = $text;
154 29         78 $self->{vchain_length} = 0;
155 29         113 $self->{data_array} = [''];
156 29         86 $self->{vchain_array} = [];
157 29         77 $self->{vchain_hash} = {};
158 29         86 $self->{actual_vcol} = {};
159 29         128 bless $self, $class;
160 29         124 $self->reset_actual_vchain();
161 29         80 return $self;
162             }
163            
164              
165              
166             ################################################################################
167             # sub load_parser
168             # Description:
169             # create a Parse::RecDescent parser
170             # and load Data::Generate grammatics into.
171             #
172             ################################################################################
173             sub load_parser
174             {
175              
176             #------------------------------------------------------------------------------#
177             # START OF GRAMMATICS #
178             #------------------------------------------------------------------------------#
179              
180 4     4 1 11 my $grammar = q {
181             start: varchar_type
182             | string_type
183             | date_type
184             | integer_type
185             | float_type
186            
187             #------------------------------------------------------------------------------#
188             # STRING TYPE GRAMMATICS #
189             #------------------------------------------------------------------------------#
190             # different intialization, but for the rest see varchar type
191              
192             string_type: ct_string vch_list
193              
194             ct_string: /STRING/
195             {
196             $Data::Generate::current->{chain_type}='STRING';
197             }
198             #------------------------------------------------------------------------------#
199             # VARCHAR TYPE GRAMMATICS #
200             #------------------------------------------------------------------------------#
201              
202             varchar_type: ct_varchar vch_list
203              
204             ct_varchar: /(VC2|VC|VARCHAR2|VARCHAR)/ '(' /\d+/ ')'
205             {
206             $Data::Generate::current->{chain_type}='VARCHAR';
207             $Data::Generate::current->{ct_length}=$item[3];
208             }
209              
210             vch_list:
211              
212             value_chain: value_col(s) vchain_weigth(?)
213             {
214             $Data::Generate::current->bind_actual_vchain();
215             1; }
216            
217             vchain_weigth: /\(/ /\d+\.?\d*/ /\%\)/
218             { $Data::Generate::current->{actual_vchain}->{weigth}=$item[2]; 1; }
219              
220             value_col: vcr_integer vcol_card(?)
221             {
222             $Data::Generate::current->bind_actual_vcol();
223             1;
224             }
225             | vcol_range
226             | vcol_literal
227             | vcol_filelist
228              
229              
230              
231             vcol_literal: vcol_lit_term vcol_card(?)
232             {
233             $Data::Generate::current->bind_actual_vcol();
234             1;
235             }
236              
237              
238             vcol_card: '{' /\d+/ '}'
239             {
240             $Data::Generate::current->{actual_vcol}->{quantifier}=$item[2];
241             1;
242             }
243              
244             vcol_lit_term: /\'.+?\'/
245             {
246             $item[1] =~ /\'(.+?)\'/;
247             push(@{$Data::Generate::current->
248             {actual_vcol}->{value_term_list}},$1); 1;
249             }
250              
251             vcol_range: vcr_start vcr_reverse(?) vcr_term(s) vcr_end vcol_card(?)
252             {
253             $Data::Generate::current->check_reverse_flag();
254             $Data::Generate::current->bind_actual_vcol();
255             1;}
256              
257              
258             vcr_start: /\[/
259              
260             vcr_reverse: /\^/ { $Data::Generate::current->{actual_vcol}
261             ->{reverse_flag}=1; }
262              
263              
264             vcr_term: /[^\s\]\[]/ '-' /[^\s\]\[]/
265             {
266             my @cmp = map(chr,
267             (
268             ord($item[1])..ord($item[3])
269             )
270             );
271             push(@{$Data::Generate::current->
272             {actual_vcol}->{value_term_list}},@cmp);
273             }
274             | '\\\\ '
275             {
276             push(@{$Data::Generate::current->
277             {actual_vcol}->{value_term_list}},' ');
278             }
279             | '\\\\' /./
280             {
281             push(@{$Data::Generate::current->
282             {actual_vcol}->{value_term_list}},$item[2]);
283             }
284             | /[^\]\[]/
285             {
286             push(@{$Data::Generate::current->
287             {actual_vcol}->{value_term_list}},$item[1]);
288             }
289              
290             vcr_end: /\]/
291              
292              
293             vcr_integer: /\[/ /\d+/ '..' /\d+/ /\]/
294             {
295             warn "false integer order " if $item[4] < $item[2];
296             my @cmp = ($item[2]..$item[4]);
297             push(@{$Data::Generate::current->
298             {actual_vcol}->{value_term_list}},@cmp);
299             }
300              
301              
302             vcol_filelist: vcol_filelist_term vcol_card(?)
303             {
304             $Data::Generate::current->bind_actual_vcol();
305             1;
306             }
307              
308              
309             vcol_filelist_term: /\<\S+\>/
310             {
311             (my $file)= ($item[1] =~ /\<(\S+)\>/);
312             $Data::Generate::current->vcol_file_process($file);
313             1;
314             }
315              
316              
317              
318            
319             #------------------------------------------------------------------------------#
320             # INTEGER TYPE GRAMMATICS #
321             #------------------------------------------------------------------------------#
322              
323             integer_type: ct_integer vch_int_list
324              
325             ct_integer: /(INTEGER|INT)/ ct_int_length(?)
326             {
327             $Data::Generate::current->{chain_type}='INTEGER';
328             $Data::Generate::current->{ct_length}=9 # max integer value
329             unless (exists $Data::Generate::current->{ct_length});
330            
331             if ($Data::Generate::current->{ct_length}>9)
332             {
333             warn " maximal integer length is 9 \n".
334             "Current Value: $Data::Generate::current->{ct_length} is too high"
335             .",will use length 9.";
336             $Data::Generate::current->{ct_length}=9;
337             }
338             }
339              
340             ct_int_length: '(' /\d+/ ')'
341             {
342             $Data::Generate::current->{ct_length}=$item[2];
343             }
344              
345             vch_int_list:
346              
347              
348             vch_int: vchi_sign(?) vcol_int(s) vchain_weigth(?)
349             {
350             $Data::Generate::current->bind_actual_vchain();
351             1; }
352              
353             vchi_sign:
354             /\+\/\-/
355             {
356             $Data::Generate::current->{actual_vchain}->{sign}->{'+'}++;
357             $Data::Generate::current->{actual_vchain}->{sign}->{'-'}++;
358             1; }
359             | /[+-]/
360             {
361             $Data::Generate::current->{actual_vchain}->{sign}->{$item[1]}++;
362             1; }
363            
364              
365              
366             vcol_int: vcint_range
367             | vcint_literal
368             | vcol_filelist
369              
370             vcint_range: /\[/ /\]/ vcint_card(?)
371             {
372             $Data::Generate::current->bind_actual_vcol();
373             1;}
374              
375              
376             vcint_term: /\d+/ '-' /\d+/
377             {
378             my @cmp = (($item[1]+0)..($item[3]+0));
379             push(@{$Data::Generate::current->
380             {actual_vcol}->{value_term_list}},@cmp);
381             }
382             | vcint_lit_term
383              
384             vcint_literal: vcint_lit_term vcint_card(?)
385             {
386             $Data::Generate::current->bind_actual_vcol();
387             1;
388             }
389              
390             vcint_lit_term: /\d+/
391             {
392             push(@{$Data::Generate::current->
393             {actual_vcol}->{value_term_list}},($item[1]+0));
394             }
395              
396             vcint_card: '{' /\d+/ '}'
397             {
398             $Data::Generate::current->{actual_vcol}->{quantifier}=$item[2];
399             1;
400             }
401              
402             #------------------------------------------------------------------------------#
403             # FLOAT TYPE GRAMMATICS #
404             #------------------------------------------------------------------------------#
405              
406             float_type: ct_float vch_float_list
407              
408             ct_float: /FLOAT/ '(' /\d+/ ')'
409             {
410             $Data::Generate::current->{chain_type}='FLOAT';
411             $Data::Generate::current->{ct_length}=$item[3];
412             }
413            
414             vch_float_list:
415            
416              
417              
418             vch_float: vchfloat_filelist
419             | vcol_float_int_part vcol_float_fraction vcol_float_exponent(?) vchain_weigth(?)
420             {
421             $Data::Generate::current->{actual_vchain}
422             ->{chain_subtype}='FLOATTOTAL';
423             $Data::Generate::current->bind_actual_vchain();
424             1; }
425            
426              
427             vchfloat_filelist: /\<\S+\>/
428             {
429             $Data::Generate::current->{actual_vchain}
430             ->{chain_subtype}='FLOATLIST';
431             (my $file)= ($item[1] =~ /\<(\S+)\>/);
432             $Data::Generate::current->vcol_file_process($file);
433             $Data::Generate::current->bind_actual_vcol();
434             $Data::Generate::current->bind_actual_vchain();
435             1;
436             }
437              
438              
439              
440             vcol_float_int_part: vchi_sign(?) vcol_int(s)
441             {
442             $Data::Generate::current->{actual_vchain}
443             ->{chain_subtype}='FLOATINTPART';
444             $Data::Generate::current->bind_actual_vchain();
445             1; }
446              
447              
448             vcol_float_exponent: 'E' vcfloat_exp_sign(?) vcfloat_exp_term
449             {
450             $Data::Generate::current->{actual_vchain}
451             ->{chain_subtype}='FLOATEXP';
452             $Data::Generate::current->bind_actual_vchain();
453             1; }
454              
455              
456             vcfloat_exp_sign: /[+-]/
457             {
458             $Data::Generate::current->{actual_vchain}->{sign}->{$item[1]}++;
459             1; }
460              
461              
462             vcfloat_exp_term: vcfloatexp_lit_term
463             {
464             $Data::Generate::current->bind_actual_vcol();
465             1;
466             }
467              
468             vcfloatexp_lit_term: /\d+/
469             {
470             push(@{$Data::Generate::current->
471             {actual_vcol}->{value_term_list}},($item[1]+0));
472             1;
473             }
474              
475             vcol_float_fraction: '.' vcol_fraction
476             {
477             $Data::Generate::current->{actual_vchain}
478             ->{chain_subtype}='FLOATFRACTION';
479             $Data::Generate::current->bind_actual_vchain();
480             1;
481             }
482              
483              
484             #------------------------------------------------------------------------------#
485             # DATE TYPE GRAMMATICS #
486             #------------------------------------------------------------------------------#
487              
488             date_type: ct_date ct_date_precision(?) vch_date_list
489              
490             ct_date: /(DT|DATE)/
491             {
492             $Data::Generate::current->{chain_type}='DATE';
493             $Data::Generate::current->{ct_length}=17;
494             }
495              
496             ct_date_precision: '(' /\d+/ ')'
497             {
498             $Data::Generate::current->{ct_precision}=$item[2];
499             if ($Data::Generate::current->{ct_precision}>14)
500             {
501             warn " maximal precision for fraction of seconds is 14 \n".
502             "Current Value: $Data::Generate::current->{ct_precision} is too high"
503             .",will use precision 14.";
504             $Data::Generate::current->{ct_precision}=14;
505             }
506              
507             $Data::Generate::current->{ct_length}+=
508             $Data::Generate::current->{ct_precision}+1; # +1 because of dot sign
509             }
510              
511              
512              
513             vch_date_list:
514              
515             vch_date: vcol_year vcol_month vcol_day vcol_time(?) vchain_weigth(?)
516             {
517             $Data::Generate::current->bind_actual_vchain();
518             1; }
519             | vchdate_filelist
520              
521              
522             vchdate_filelist: /\<\S+\>/
523             {
524             (my $file)= ($item[1] =~ /\<(\S+)\>/);
525             $Data::Generate::current->vcol_file_process($file);
526             $Data::Generate::current->bind_actual_vcol();
527             $Data::Generate::current->bind_actual_vchain();
528             1;
529             }
530              
531              
532             vcol_time: vcol_hour ':' vcol_min ':' vcol_sec vcol_date_fraction(?)
533              
534             vcol_year: vcdate_range
535             { $Data::Generate::current->bind_vcol_range('year'); 1;}
536             | vcdate_literal
537             { $Data::Generate::current->bind_vcol_literal('year'); 1;}
538              
539             vcol_month: vcmonth_range
540             { $Data::Generate::current->bind_vcol_range('month'); 1;}
541             | vcmonth_literal
542             {
543             my $litval=shift(@{$Data::Generate::current->{actual_vcol}->{month_literal_values}});
544             $Data::Generate::current->{actual_vcol}->{literal_value}=$litval;
545             $Data::Generate::current->bind_vcol_literal('month'); 1;}
546              
547             vcol_day: vcday_range
548             { $Data::Generate::current->bind_vcol_range('day'); 1;}
549             | vcdate_literal
550             { $Data::Generate::current->bind_vcol_literal('day'); 1;}
551              
552             vcol_hour: vcdate_range
553             { $Data::Generate::current->bind_vcol_range('hour'); 1;}
554             | vcdate_literal
555             { $Data::Generate::current->bind_vcol_literal('hour'); 1;}
556              
557             vcol_min: vcdate_range
558             { $Data::Generate::current->bind_vcol_range('minute'); 1;}
559             | vcdate_literal
560             { $Data::Generate::current->bind_vcol_literal('minute'); 1;}
561              
562             vcol_sec: vcdate_range
563             { $Data::Generate::current->bind_vcol_range('sec'); 1;}
564             | vcdate_literal
565             { $Data::Generate::current->bind_vcol_literal('sec'); 1;}
566              
567             vcol_date_fraction: '.' vcol_fraction
568             {
569             $Data::Generate::current->{actual_vchain}
570             ->{chain_subtype}='DATEWITHFRACTION';
571             1;
572             }
573              
574             vcdate_literal: /\d+/
575             {
576             $Data::Generate::current->{actual_vcol}->{literal_value}=$item[1];
577             1;
578             }
579              
580            
581             vcdate_range: /\[/ /\]/
582              
583             vcdate_term: /\d+/ '-' /\d+/
584             { $Data::Generate::current->add_term_range($item[1],$item[3]);1; }
585             | /\d+/
586             {
587             push(@{$Data::Generate::current->{actual_vcol}->{value_term_list}},
588             $item[1]); 1;
589             }
590              
591              
592             vcday_range: /\[/ /\]/
593            
594             vcday_term: vcdate_term
595             |
596             {
597             my $low =shift(@{$Data::Generate::current->{actual_vcol}->{weekday_index_values}});
598             my $high =shift(@{$Data::Generate::current->{actual_vcol}->{weekday_index_values}});
599             push(@{$Data::Generate::current->{actual_vcol}->{weekday_term_list}},
600             $low) unless defined $high;
601             $Data::Generate::current-> add_weekday_term_range($low,$high)
602             if defined $high;
603             1;
604             }
605              
606              
607             vcday_literal: /[a-zA-Z]+/
608             {
609             my @week=@{$Data::Generate::vcol_type->{weekday}->{term_list}};
610             my $ix=-1;
611             foreach my $wday_ix (0..$#week)
612             {
613             $ix=$wday_ix if $item[1] =~ /^$week[$wday_ix]/i;
614             }
615             die "cant process day term $item[1] " if $ix==-1;
616             push(@{$Data::Generate::current->{actual_vcol}->{weekday_index_values}}
617             ,$ix);
618             1;
619             }
620              
621             vcmonth_range: /\[/ /\]/
622              
623             vcmonth_term:
624             {
625             my $low =shift(@{$Data::Generate::current->{actual_vcol}->{month_literal_values}});
626             my $high =shift(@{$Data::Generate::current->{actual_vcol}->{month_literal_values}});
627             push(@{$Data::Generate::current->{actual_vcol}->{value_term_list}},
628             $low) unless defined $high;
629             $Data::Generate::current->add_term_range($low,$high)
630             if defined $high;
631             1;
632             }
633              
634             vcmonth_literal: /(\d+|[a-zA-Z]+)/
635             {
636             my $month=undef;
637             if ($item[1] =~ /\d+/)
638             {
639             $month =$item[1];
640             }
641             else
642             {
643             (undef,undef,undef,undef,$month,undef,undef) = Date::Parse::strptime($item[1].' 01');
644             die "Month $item[2] invalid " unless defined $month;
645             ++$month;
646             }
647             push(@{$Data::Generate::current->{actual_vcol}->{month_literal_values}}
648             ,$month);
649             1;
650             }
651              
652             #------------------------------------------------------------------------------#
653             # FRACTION SUBTYPE GRAMMATICS #
654             # (RELEVANT FOR DATE AND FLOAT) #
655             #------------------------------------------------------------------------------#
656              
657             vcol_fraction: vcol_fract(s)
658              
659             vcol_fract: vcfract_range
660             | vcfract_literal
661              
662             vcfract_range: /\[/ /\]/ vcfract_card(?)
663             {
664             $Data::Generate::current->bind_actual_vcol();
665             1;}
666              
667              
668             vcfract_term: /\d+/ '-' /\d+/
669             {
670             my @cmp = (($item[1]+0)..($item[3]+0));
671             push(@{$Data::Generate::current->
672             {actual_vcol}->{value_term_list}},@cmp);
673             }
674             | vcfract_lit_term
675              
676             vcfract_literal: vcfract_lit_term vcfract_card(?)
677             {
678             $Data::Generate::current->bind_actual_vcol();
679             1;
680             }
681              
682             vcfract_lit_term: /\d+/
683             {
684             push(@{$Data::Generate::current->
685             {actual_vcol}->{value_term_list}},($item[1]+0));
686             }
687              
688             vcfract_card: '{' /\d+/ '}'
689             {
690             $Data::Generate::current->{actual_vcol}->{quantifier}=$item[2];
691             1;
692             }
693             };
694             #------------------------------------------------------------------------------#
695             # END OF GRAMMATICS #
696             #------------------------------------------------------------------------------#
697              
698 4         46 my $parser = Parse::RecDescent->new($grammar);
699 4 50       2173718 defined $parser or carp "couldn't load parser";
700 4         21 return $parser;
701              
702             }
703              
704              
705             ################################################################################
706             # Description: helper function
707             ################################################################################
708             sub check_reverse_flag
709             {
710 12     12 1 46915 my $self =shift;
711 12 100       391 return unless exists $self->{actual_vcol}->{reverse_flag};
712 1         7 $self->{actual_vcol}->{value_term_list}=
713             $self->get_value_column_reverse($self->{actual_vcol}->{value_term_list});
714 1         41 delete $self->{actual_vcol}->{reverse_flag};
715             }
716              
717             ################################################################################
718             # Description: helper function
719             ################################################################################
720             sub check_range_order ($$)
721             {
722 16     16 1 21 my $min =shift;
723 16         21 my $max =shift;
724 16 50       59 if ($min >$max )
725             {
726 0         0 carp "false range order, $min > $max".
727             " will invert limits";
728 0         0 return [$max, $min];
729             }
730 16         71 return [$min, $max];
731             }
732              
733             ################################################################################
734             # sub vcol_file_process
735             # Description: read vcol_terms from file
736             #
737             ################################################################################
738             sub vcol_file_process
739             {
740 5     5 1 20075 my $self =shift;
741 5         13 my $file =shift;
742 5 50       292 open(VCOLFILE,$file) or carp "Couldnt open term file $file ";
743 5         191 my @cmp = ();
744 5         158 close(VCOLFILE);
745 5 50       23 @cmp=('') if $#cmp==-1;
746 5         27 map(chomp($_),@cmp);
747 5 100 66     57 if (exists $Data::Generate::vchain_type->{$self->{chain_type}}
748             && exists $Data::Generate::vchain_type->{$self->{chain_type}}->{check_type}
749             )
750             {
751 3         9 my @cmp2=();
752 3         10 foreach my $element (@cmp)
753             {
754 19         80 my $result=
755 19         30 &{$Data::Generate::vchain_type->{$self->{chain_type}}->{check_type}}
756             ($element);
757 19 100       685 push(@cmp2,$result) if defined $result;
758             }
759 3         17 @cmp=@cmp2;
760             };
761 5         13 my $uniq={};
762 5         47 map($uniq->{$_}++,@cmp);
763 5         30 @cmp=(keys %$uniq);
764 5         12 push(@{$self->{actual_vcol}->{value_term_list}},@cmp);
  5         200  
765             }
766              
767              
768              
769              
770             ################################################################################
771             # sub vcol_date_process
772             # Description: processing action for dates.
773             # At the end of each date production the three vcol date types year month day
774             # will be merged to a single one, so that date validity can be assessed,
775             # therefore instead of normally adding the date columns year and month,
776             # we keep them aside until the day column is processed.
777             #
778             ################################################################################
779             sub vcol_date_process
780             {
781 24     24 1 35 my $self =shift;
782 24 100       122 if ($self->{actual_vcol}->{type} =~ /^(month|year)$/ )
783             {
784 16         41 my $type=$self->{actual_vcol}->{type};
785 16         28 $type.='_vcol';
786 16         42 $self->{$type} = $self->{actual_vcol};
787 16         34 return;
788             }
789 8 50       35 die "internal eror" if ($self->{actual_vcol}->{type} ne 'day' );
790 8         28 $self->{day_vcol} = $self->{actual_vcol};
791 8         21 $self->{actual_vcol}={};
792 8         20 my @value_term_list=();
793 8         16 my $weekdays={};
794 8 100       40 if (exists $self->{day_vcol}->{weekday_term_list})
795             {
796 2         4 foreach my $day_term (@{$self->{day_vcol}->{weekday_term_list}})
  2         7  
797             {
798 6         18 $weekdays->{$day_term}++
799             }
800             }
801 8         19 foreach my $year_term (@{$self->{year_vcol}->{value_term_list}})
  8         25  
802             {
803 12         795 foreach my $month_term (@{$self->{month_vcol}->{value_term_list}})
  12         41  
804             {
805 28         2759 my $monthdays={};
806 28         39 foreach my $day_term (@{$self->{day_vcol}->{value_term_list}})
  28         83  
807             {
808             # convert 'char dates in numeric ones like '07'-> 7
809             # otherwise we cannot make unique value set
810 99         112 $day_term+=0;
811 99         226 $monthdays->{$day_term}++
812             }
813 28         128 my $first_month_weekday=dayofweek( 01,$month_term, $year_term );
814 28         909 foreach my $wkday_term (keys %{$weekdays})
  28         97  
815             {
816 24         47 my $day_term=$wkday_term-$first_month_weekday+1;
817 24 100       51 $day_term+=7 if $day_term<1;
818 24         52 while ($day_term<31)
819             {
820 104         171 $monthdays->{$day_term}++;
821 104         207 $day_term+=7;
822             }
823             }
824 28         48 foreach my $day_term (keys %{$monthdays})
  28         107  
825             {
826 200         29460 my $date_term =
827             sprintf('%04d%02d%02d',$year_term, $month_term, $day_term);
828 200 50       528 push(@value_term_list,$date_term)
829             if defined str2time($date_term);
830             }
831             }
832             }
833 8         1784 @value_term_list=sort(@value_term_list);
834 8         35 $self->{actual_vcol}->{value_term_list}=\@value_term_list;
835              
836 8         51 $self->add_value_column($self->{actual_vcol}->{value_term_list});
837 8         38 delete $self->{year_vcol};
838 8         33 delete $self->{month_vcol};
839 8         38 delete $self->{day_vcol};
840              
841             }
842              
843              
844             ################################################################################
845             # sub vchain_date_fraction_process
846             # Description: reorganizes the internal vchain structure of date types with
847             # fraction values due to the possible presence of trailing zeros.
848             ################################################################################
849             sub vchain_date_fraction_process
850             {
851            
852 2     2 1 5 my $self =shift;
853 2         6 my $vchain_full=$self->{actual_vchain};
854 2         9 $self->reset_actual_vchain();
855              
856 2         4 my $vchain_fraction={};
857 2         8 $vchain_fraction->{vcol_count}=$vchain_full->{vcol_count};
858 2         48 map($vchain_fraction->{vcol_hash}->{$_}->{value_column}=
859             $vchain_full->{vcol_hash}->{$_}->{value_column},
860             (0..$vchain_fraction->{vcol_count}));
861              
862              
863 2         23 my $fraction_start=
864             $Data::Generate::vchain_type->{DATE}->{subtype}->{'DATEWITHFRACTION'}
865             ->{fraction_start_ix};
866             map_vchain_indexes($vchain_fraction,
867 14 100   14   31 sub { return undef if $_[0] <$fraction_start;
868 6         12 return $vchain_fraction->{vcol_count}-$_[0];
869             }
870 2         16 );
871 2         10 $vchain_fraction->{vcol_count}=$vchain_full->{vcol_count}-
872             $fraction_start;
873              
874 2         4 my $vchain_data={};
875 2         8 $vchain_data->{weigth}=$vchain_full->{weigth};
876 2         11 my $vchain_weigth_list=$self->vchain_number_reprocess($vchain_fraction);
877              
878 2         6 foreach my $vchain (@$vchain_weigth_list)
879             {
880 8         13 $vchain->{vcol_count}+=$fraction_start;
881             map_vchain_indexes($vchain,
882 46     46   87 sub { return $vchain->{vcol_count}-$_[0];
883             }
884 8         32 );
885 8         77 map($vchain->{vcol_hash}->{$_}->{value_column}=
886             $vchain_full->{vcol_hash}->{$_}->{value_column},
887             (0..$fraction_start-1));
888             }
889              
890             # weigth has to be recalculated now.
891 2         11 calculate_vchain_list_weigth($vchain_weigth_list,$vchain_data->{weigth});
892              
893              
894 2         16 1;
895             }
896              
897              
898             ################################################################################
899             # sub vchain_fraction_process
900             # Description: reorganizes the internal vchain structure of a fractional
901             # vchain part due to the possible presence of trailing zeros.
902             ################################################################################
903             sub vchain_fraction_process
904             {
905            
906 8     8 1 20 my $self =shift;
907 8         24 my $vchain_fraction =$self->{actual_vchain};
908 8         259 $self->reset_actual_vchain();
909             map_vchain_indexes($vchain_fraction,
910             sub {
911 15     15   55 return $vchain_fraction->{vcol_count}-$_[0];
912             }
913 8         60 );
914 8         30 my $vchain_data={};
915 8         31 $vchain_data->{weigth}=$vchain_fraction->{weigth};
916 8         46 my $vchain_weigth_list=$self->vchain_number_reprocess($vchain_fraction);
917              
918 8         23 foreach my $vchain (@$vchain_weigth_list)
919             {
920             map_vchain_indexes($vchain,
921 20     20   46 sub { return $vchain->{vcol_count}-$_[0];
922             }
923 13         60 );
924             }
925 8         35 return $vchain_weigth_list;
926              
927              
928 0         0 1;
929             }
930              
931              
932             ################################################################################
933             # sub merge_vchain_float_lists
934             # Description: merge int and float vchain lists together.(and add a '.' inbet.)
935             ################################################################################
936             sub merge_vchain_float_lists
937             {
938 8     8 1 16 my $self =shift;
939 8         17 my $vchain_sign_list =shift;
940 8         12 my $vchain_integer_list =shift;
941 8         14 my $vchain_float_list =shift;
942 8         16 my $vchain_exp_list =shift;
943 8         17 my $vchain_merge_list =[];
944 8         17 my $vchain_zero =undef;
945 8         19 foreach my $vchain_integer (@$vchain_integer_list)
946             {
947 12     26   61 map_vchain_indexes($vchain_integer, sub { return 1+$_[0] ;});
  26         54  
948 12         51 $vchain_integer->{vcol_hash}->{0}->{value_column}=$vchain_sign_list;
949 12         33 $vchain_integer->{vcol_count}++;
950             }
951 8 50       41 if (@$vchain_exp_list ==0)
952             {
953 0         0 my $vchain_exp={};
954 0         0 $vchain_exp->{vcol_hash}->{0}->{value_column}=['0'];
955 0         0 $vchain_exp->{vcol_count}++;
956 0         0 push(@$vchain_exp_list,$vchain_exp);
957             }
958 8         21 foreach my $vchain_exp (@$vchain_exp_list)
959             {
960 8     9   45 map_vchain_indexes($vchain_exp, sub { return 1+$_[0] ;});
  9         21  
961 8         45 $vchain_exp->{vcol_hash}->{0}->{value_column}=['E'];
962 8         36 $vchain_exp->{vcol_count}++;
963             }
964 8         21 my $vchain_exp = $vchain_exp_list->[0];
965 8         33 foreach my $vchain_integer (@$vchain_integer_list)
966             {
967 12         27 foreach my $vchain_float (@$vchain_float_list)
968             {
969 25         39 foreach my $vchain_exp (@$vchain_exp_list)
970             {
971 25         43 my $vchain_merged={};
972 25         63 $vchain_merged->{vcol_count}=$vchain_integer->{vcol_count};
973 25         205 map($vchain_merged->{vcol_hash}->{$_}->{value_column}=
974             $vchain_integer->{vcol_hash}->{$_}->{value_column},
975             (0..$vchain_integer->{vcol_count}));
976 25         48 $vchain_merged->{vcol_count}++;
977 25         100 $vchain_merged->{vcol_hash}->{$vchain_merged->{vcol_count}}->{value_column}=['.'];
978              
979 25         175 map($vchain_merged->{vcol_hash}->{$vchain_merged->{vcol_count}+1+$_}
980             ->{value_column}=$vchain_float->{vcol_hash}->{$_}->{value_column},
981             (0..$vchain_float->{vcol_count}));
982 25         58 $vchain_merged->{vcol_count}+=$vchain_float->{vcol_count}+1;
983              
984              
985             # avoid double +/-0.0 , skip exp processing
986 25 100 100     32 if (($#{$vchain_merged->{vcol_hash}->{1}->{value_column}}==0)
  25   66     186  
  6   66     50  
      66        
      100        
      66        
987             && ($vchain_merged->{vcol_hash}->{1}->{value_column}->[0]==0)
988 6         57 && ($#{$vchain_merged->{vcol_hash}->{2}->{value_column}}==0)
989             && ($vchain_merged->{vcol_hash}->{2}->{value_column}->[0] eq '.')
990             && ($#{$vchain_merged->{vcol_hash}->{3}->{value_column}}==0)
991             && ($vchain_merged->{vcol_hash}->{3}->{value_column}->[0]==0)
992             && ($vchain_merged->{vcol_count}==3)
993             )
994             {
995 2 50       8 next if defined $vchain_zero;
996 2         7 $vchain_merged->{vcol_hash}->{0}->{value_column}=['+'];
997 2         6 $self->bind_vchain($vchain_merged);
998 2         5 push(@$vchain_merge_list,$vchain_merged);
999 2         3 $vchain_zero=$vchain_merged;
1000 2         10 next;
1001             }
1002              
1003              
1004              
1005 23         233 map($vchain_merged->{vcol_hash}->{$vchain_merged->{vcol_count}+1+$_}
1006             ->{value_column}=$vchain_exp->{vcol_hash}->{$_}->{value_column},
1007             (0..$vchain_exp->{vcol_count}));
1008 23         53 $vchain_merged->{vcol_count}+=$vchain_exp->{vcol_count}+1;
1009            
1010 23         52 $self->bind_vchain($vchain_merged);
1011 23         86 push(@$vchain_merge_list,$vchain_merged);
1012            
1013             }
1014             }
1015             }
1016 8         23 return $vchain_merge_list;
1017              
1018 0         0 1;
1019             }
1020              
1021              
1022              
1023              
1024             ################################################################################
1025             # sub vchain_date_fraction_process
1026             # Description: reorganizes the internal vchain structure of date types with
1027             # fraction values due to the possible presence of trailing zeros.
1028             ################################################################################
1029             sub vchain_float_process
1030             {
1031 26     26 1 53 my $self =shift;
1032 26 100       113 if ($self->{actual_vchain}->{chain_subtype} eq 'FLOATLIST' )
1033             {
1034 1         6 $self->bind_vchain($self->{actual_vchain});
1035 1         5 $self->reset_actual_vchain();
1036 1         3 return;
1037             }
1038              
1039 25 100       95 if ($self->{actual_vchain}->{chain_subtype} eq 'FLOATINTPART' )
1040             {
1041 8         32 $self->{FLOAT_CHAIN_START}=1+$#{$self->{vchain_array}};
  8         37  
1042 8         29 $self->{FLOAT_CHAIN_SIGN}=[];
1043 8 100 66     85 push (@{$self->{FLOAT_CHAIN_SIGN}},'+')
  5         14  
1044             if (! exists $self->{actual_vchain}->{sign}
1045             || exists $self->{actual_vchain}->{sign}->{'+'} );
1046 8 100 66     90 push (@{$self->{FLOAT_CHAIN_SIGN}},'-')
  5         17  
1047             if ( exists $self->{actual_vchain}->{sign}
1048             && exists $self->{actual_vchain}->{sign}->{'-'} );
1049              
1050 8         18 my $actual_vchain= $self->{actual_vchain};
1051 8         46 $self->reset_actual_vchain();
1052 8         57 $self->{FLOAT_INTEGER_PART}=$self->vchain_number_reprocess($actual_vchain);
1053 8         19 return;
1054              
1055             }
1056              
1057              
1058              
1059 17 100       73 if ($self->{actual_vchain}->{chain_subtype} eq 'FLOATFRACTION' )
1060             {
1061 8         40 $self->{FLOAT_FRACTION_PART}=$self->vchain_fraction_process();
1062 8         28 my $actual_vchain= $self->{actual_vchain};
1063 8         25 $self->reset_actual_vchain();
1064 8         23 return;
1065             }
1066 9 100       143 if ($self->{actual_vchain}->{chain_subtype} eq 'FLOATEXP' )
1067             {
1068 1         4 $self->{FLOAT_EXP_PART}=$self->vchain_integer_process();
1069 1         3 return;
1070             }
1071              
1072              
1073              
1074              
1075              
1076 8 50       38 croak "Error in float parsing $self->{actual_vchain}->{chain_subtype} "
1077             unless $self->{actual_vchain}->{chain_subtype} eq 'FLOATTOTAL';
1078             # print "*********************".$self->{actual_vchain}->{weigth}."\n";
1079 8         37 $self->{FLOAT_CHAIN_WEIGTH}=$self->{actual_vchain}->{weigth};
1080              
1081 8 100       35 unless (exists $self->{FLOAT_EXP_PART})
1082             {
1083 7         23 $self->{actual_vchain}->{chain_subtype}= 'FLOATEXP';
1084 7         13 push(@{$self->{actual_vcol}->{value_term_list}},0);
  7         27  
1085 7         24 $self->bind_actual_vcol();
1086 7         29 $self->{FLOAT_EXP_PART}=$self->vchain_integer_process();
1087 7         24 $self->{zzzzFLOAT_EXP_PART}=$self->{FLOAT_EXP_PART};
1088             }
1089              
1090 8         41 foreach my $vchain_id ($self->{FLOAT_CHAIN_START}..$#{$self->{vchain_array}})
  8         28  
1091             {
1092 33         70 delete $self->{vchain_hash}->{$vchain_id};
1093 33         39 pop(@{$self->{vchain_array}});
  33         67  
1094             }
1095 8         52 my $merge_list=$self->merge_vchain_float_lists($self->{FLOAT_CHAIN_SIGN},
1096             $self->{FLOAT_INTEGER_PART},
1097             $self->{FLOAT_FRACTION_PART},
1098             $self->{FLOAT_EXP_PART});
1099 8         31 calculate_vchain_list_weigth($merge_list,$self->{FLOAT_CHAIN_WEIGTH});
1100 8         18 delete $self->{FLOAT_CHAIN_START};
1101 8         19 delete $self->{FLOAT_CHAIN_SIGN};
1102 8         26 delete $self->{FLOAT_CHAIN_WEIGTH};
1103 8         53 delete $self->{FLOAT_INTEGER_PART};
1104 8         39 delete $self->{FLOAT_FRACTION_PART};
1105 8         20 delete $self->{FLOAT_EXP_PART};
1106              
1107 8         20 1;
1108             }
1109              
1110              
1111              
1112             ################################################################################
1113             # sub vchain_integer_process
1114             # Description: reorganizes the internal vchain structure of integer types.
1115             # due to the possible presence of leading zeros.
1116             ################################################################################
1117             # INT (9) +/- [3,0] [21,3,0] [4,0]
1118             #
1119             # + 0 0 4 -> converted to + 0 | + 3 0 4 | + 21 4| + 4
1120             # - 3 21 0 | - 21 0 | - 3 0| -
1121             # 3 | 3 | |
1122             # | | |
1123             #
1124             # degr of freedom = 1 + 12 + 8 + 2 = 23
1125             # -210','-214','-30','-300','-304','-3210','-3214','-330','-334','-34','-4','0','210','214','30','300',
1126             # '304','3210','3214
1127             sub vchain_integer_process
1128             {
1129            
1130 13     13 1 33 my $self =shift;
1131 13         34 my $last_vchain=$self->{actual_vchain};
1132 13         58 $self->reset_actual_vchain();
1133 13         26 my $vchain_data={};
1134 13         52 $vchain_data->{weigth}=$last_vchain->{weigth};
1135              
1136 13 100 100     97 push (@{$vchain_data->{sign}},'+')
  11         173  
1137             if (! exists $last_vchain->{sign} || exists $last_vchain->{sign}->{'+'} );
1138 13 100 66     86 push (@{$vchain_data->{sign}},'-')
  3         11  
1139             if ( exists $last_vchain->{sign} && exists $last_vchain->{sign}->{'-'} );
1140 13         32 delete $last_vchain->{sign};
1141 13         48 my $vchain_weigth_list=$self->vchain_number_reprocess($last_vchain);
1142              
1143 13         43 foreach my $vchain (@$vchain_weigth_list)
1144             {
1145 13         8681 next if $vchain->{vcol_count}==0
1146 19 100 100     86 && @{$vchain->{vcol_hash}->{0}->{value_column}}==1
      100        
1147             && $vchain->{vcol_hash}->{0}->{value_column}->[0]==0;
1148 10     23   54 map_vchain_indexes($vchain,sub { return 1+$_[0];});
  23         45  
1149 10         34 $vchain->{vcol_count}++;
1150 10         13 @{$vchain->{vcol_hash}->{0}->{value_column}}=@{$vchain_data->{sign}};
  10         54  
  10         36  
1151             }
1152             # weigth has to be recalculated now.
1153 13         63 calculate_vchain_list_weigth($vchain_weigth_list,$vchain_data->{weigth});
1154 13         78 return $vchain_weigth_list;
1155             }
1156              
1157              
1158              
1159             ################################################################################
1160             # sub vchain_number_reprocess
1161             # Description: reorganizes the internal vchain structure of numeric types.
1162             # Due to the possible presence of leading or trailing zeros, we have to
1163             # restructure the vcols in vchains to avoid duplicates (001, 01 problem).
1164             # Other solutions are either too memory intensive (build the output values at
1165             # vchain binding) or lead to incorrect cardinality calculation (eliminate
1166             # duplicates at output data production);
1167             ################################################################################
1168             # INT (9) +/- [3,0] [21,3,0] [4,0]
1169             #
1170             # + 0 0 4 -> converted to + 0 | + 3 0 4 | + 21 4| + 4
1171             # - 3 21 0 | - 21 0 | - 3 0| -
1172             # 3 | 3 | |
1173             # | | |
1174             #
1175             # degr of freedom = 1 + 12 + 8 + 2 = 23
1176             # -210','-214','-30','-300','-304','-3210','-3214','-330','-334','-34','-4','0','210','214','30','300',
1177             # '304','3210','3214','330','334','34','4
1178             sub vchain_number_reprocess
1179             {
1180 31     31 1 57 my $self =shift;
1181 31         53 my $last_vchain =shift;
1182            
1183 31         61 my $vcol_nonzero_list=[];
1184 31         62 my $vcol_zero_list=[];
1185 31         70 my $vchain_weigth_list=[];
1186            
1187 31         121 while($last_vchain->{vcol_count}>=0)
1188             {
1189 46         106 my $vcol_list=
1190             $last_vchain->{vcol_hash}->{0}->{value_column};
1191            
1192 46         99 $vcol_nonzero_list=[];
1193 46         79 $vcol_zero_list=[];
1194 46         109 foreach my $vcol_value (@$vcol_list)
1195             {
1196 104 100       375 push (@$vcol_nonzero_list,$vcol_value) unless $vcol_value =~ /^0+$/;
1197 104 100       357 push (@$vcol_zero_list,$vcol_value) if $vcol_value =~ /^0+$/;
1198             }
1199 46 100       170 if(@$vcol_nonzero_list >0)
1200             {
1201 36         81 $last_vchain->{vcol_hash}->{0}->{value_column}
1202             =$vcol_nonzero_list;
1203 36         113 $self->bind_vchain($last_vchain);
1204 36         119 push(@$vchain_weigth_list,$self->{vchain_hash}
1205 36         173 ->{$#{$self->{vchain_array}}});
1206             }
1207 46 100       155 last unless(@$vcol_zero_list>0);
1208 31         54 my $next_vchain={};
1209 31         81 $next_vchain->{vcol_count}=$last_vchain->{vcol_count};
1210 31         219 map($next_vchain->{vcol_hash}->{$_}->{value_column}=
1211             $last_vchain->{vcol_hash}->{$_}->{value_column},
1212             (0..$last_vchain->{vcol_count}));
1213             map_vchain_indexes($next_vchain,sub {
1214 51 100   51   158 return undef if $_[0]==0;
1215 20         38 return $_[0]-1;
1216 31         160 });
1217 31         107 $next_vchain->{vcol_count}--;
1218 31         107 $last_vchain=$next_vchain;
1219             }
1220 31 100       124 if (@$vcol_zero_list>0)
1221             {
1222             # add now 0 chain in place of +/-
1223 16         60 $last_vchain->{vcol_hash}->{0}->{value_column}=[0];
1224 16         29 $last_vchain->{vcol_count}++;
1225 16         46 $self->bind_vchain($last_vchain);
1226 16         48 push(@$vchain_weigth_list,$self->{vchain_hash}
1227 16         38 ->{$#{$self->{vchain_array}}});
1228             }
1229 31         109 return $vchain_weigth_list;
1230             }
1231              
1232             ################################################################################
1233             # Description: helper function. Calculate weigth for a group of vchains
1234             ################################################################################
1235             sub calculate_vchain_list_weigth
1236             {
1237 23     23 1 43 my $vchain_list =shift;
1238 23         43 my $weigth =shift;
1239 23         78 my $card=
1240             calculate_vchain_list_degrees_of_freedom($vchain_list);
1241 23         172 map($_->{weigth}=$weigth,@$vchain_list);
1242 23         99 map($_->{weigth}*=$_->{vchain_card},@$vchain_list);
1243 23         95 map($_->{weigth}/=$card,@$vchain_list);
1244             }
1245              
1246             ################################################################################
1247             # Description: helper function.Change internal vcol indexes of a vchain
1248             ################################################################################
1249             sub map_vchain_indexes
1250             {
1251 92     92 1 136 my $vchain =shift;
1252 92         119 my $change_function =shift;
1253 92         218 foreach my $index (0..$vchain->{vcol_count})
1254             {
1255 204         364 my $new_index=&$change_function($index);
1256 204 100       503 next unless defined $new_index;
1257 165         728 $vchain->{vcol_hash_tmp}->{$new_index}->{value_column}=
1258             $vchain->{vcol_hash}->{$index}->{value_column};
1259             }
1260 92         207 $vchain->{vcol_hash}=$vchain->{vcol_hash_tmp};
1261 92         345 delete $vchain->{vcol_hash_tmp};
1262             }
1263              
1264              
1265             ################################################################################
1266             # Description: helper function
1267             ################################################################################
1268             sub check_input_limits
1269             {
1270 101     101 1 286 my $type =shift;
1271 101         133 my $value =shift;
1272            
1273             # no type defined, no ranges to check
1274 101 50       246 return unless defined $type;
1275 101 100       305 return unless exists $Data::Generate::vcol_type->{$type};
1276              
1277 85         142 my $limit_check_hash=$Data::Generate::vcol_type->{$type};
1278 85 50 33     655 if ((exists $limit_check_hash->{lowlimit}) &&
1279             (defined $limit_check_hash->{lowlimit}))
1280             {
1281 85 50       232 croak " $limit_check_hash->{type} went out of range,".
1282             " $value < $limit_check_hash->{lowlimit} "
1283             if $value < $limit_check_hash->{lowlimit};
1284             }
1285 85 50 33     621 if ((exists $limit_check_hash->{highlimit}) &&
1286             (defined $limit_check_hash->{highlimit}))
1287             {
1288 85 50       319 croak " $limit_check_hash->{type} went out of range,".
1289             " $value > $limit_check_hash->{highlimit} "
1290             if $value > $limit_check_hash->{highlimit};
1291             }
1292             }
1293              
1294              
1295             ################################################################################
1296             # sub # vcol_add_term_range
1297             # Description:
1298             # add an expression (a..b) after parsing
1299             ################################################################################
1300             sub add_weekday_term_range
1301             {
1302 2     2 1 5828 my $self =shift;
1303 2         5 my $min =shift;
1304 2         4 my $max =shift;
1305 2         4 my $act_vcol=$self->{actual_vcol};
1306 2 50       34 if ($min>$max)
1307             {
1308             # index 6 is sunday
1309 0         0 push(@{$self->{actual_vcol}->{weekday_term_list}},($min..6));
  0         0  
1310             # index 0 is monday
1311 0         0 push(@{$self->{actual_vcol}->{weekday_term_list}},(0..$max));
  0         0  
1312 0         0 return;
1313             }
1314 2         3 push(@{$self->{actual_vcol}->{weekday_term_list}},($min..$max));
  2         47  
1315             }
1316              
1317              
1318             ################################################################################
1319             # sub # vcol_add_term_range
1320             # Description:
1321             # add an expression (a..b) after parsing
1322             ################################################################################
1323             sub add_term_range
1324             {
1325 16     16 1 20110 my $self =shift;
1326 16         28 my $min =shift;
1327 16         23 my $max =shift;
1328 16         41 my $minmax=check_range_order($min,$max);
1329 16         35 my $act_vcol=$self->{actual_vcol};
1330 16         21 push(@{$self->{actual_vcol}->{value_term_list}},
  16         453  
1331             ($minmax->[0]..$minmax->[1]));
1332             }
1333              
1334              
1335             ################################################################################
1336             # sub # add_value_column_range
1337             # Description:
1338             # add an expression (a..b) after parsing
1339             ################################################################################
1340             sub bind_vcol_range
1341             {
1342 21     21 1 18960 my $self =shift;
1343 21         38 my $type =shift;
1344 21         47 my $act_vcol=$self->{actual_vcol};
1345 21         33 foreach my $value (@{$self->{actual_vcol}->{value_term_list}})
  21         234  
1346             {
1347 74         136 check_input_limits($type,$value);
1348             }
1349 21         45 $act_vcol->{type}=$type;
1350 21         59 $self->bind_actual_vcol();
1351             }
1352              
1353              
1354              
1355             ################################################################################
1356             # sub # add_value_column_range
1357             # Description:
1358             # add an expression (a..b) after parsing
1359             ################################################################################
1360             sub bind_vcol_literal
1361             {
1362 27     27 1 27778 my $self =shift;
1363 27         51 my $type =shift;
1364 27         48 my $act_vcol=$self->{actual_vcol};
1365 27         80 check_input_limits($type,$self->{actual_vcol}->{literal_value});
1366 27         96 $self->{actual_vcol}->{value_term_list}=
1367             [$act_vcol->{literal_value}];
1368 27         47 $act_vcol->{type}=$type;
1369 27         74 $self->bind_actual_vcol();
1370             }
1371              
1372              
1373             ################################################################################
1374             # sub # sub set_actual_vchain_weigth
1375             # Description:
1376             # add weigth to actual value chain
1377             ################################################################################
1378             sub reset_actual_vchain
1379             {
1380 90     90 1 179 my $self =shift;
1381 90         418 $self->{actual_vchain} = {};
1382 90         254 $self->{actual_vchain}->{vchain_length} = 0;
1383 90         721 $self->{actual_vchain}->{weigth}=100;
1384             }
1385              
1386             ################################################################################
1387             # sub bind_actual_vcol
1388             # Description: Postprocessing action.
1389             # At the end of each value column production, add actual value column to the
1390             # actual vchain. Afterwards reset actual_vcol to an empty hash
1391             #
1392             ################################################################################
1393             sub bind_actual_vcol
1394             {
1395 123     123 1 142365 my $self =shift;
1396 123         230 my $quantifier=1;
1397 123 100       620 $quantifier=$self->{actual_vcol}->{quantifier}
1398             if exists $self->{actual_vcol}->{quantifier};
1399            
1400              
1401 123 100 100     1158 if ((defined $self->{actual_vcol}->{type} ) &&
    50 66        
1402             ($self->{actual_vcol}->{type} =~ /^(day|month|year)$/ ))
1403             {
1404 24         75 $self->vcol_date_process();
1405             }
1406             elsif ((defined $self->{actual_vcol}->{type} ) &&
1407             ($self->{actual_vcol}->{type} eq 'sign' ))
1408             {
1409 0         0 $self->{sign_value_list}=$self->{actual_vcol}->{value_term_list};
1410 0         0 $self->reset_actual_vcol();
1411             }
1412             else
1413             {
1414             $self->add_value_column($self->{actual_vcol}->{value_term_list})
1415 99         663 foreach(1..$quantifier);
1416             }
1417 123         287 $self->{actual_vcol} = {};
1418 123         3787 $self->{actual_vcol}->{type} = undef;
1419             }
1420              
1421             sub reset_actual_vcol
1422             {
1423 0     0 1 0 my $self =shift;
1424 0         0 $self->{actual_vcol} = {};
1425 0         0 $self->{actual_vcol}->{type} = undef;
1426             }
1427              
1428              
1429             ################################################################################
1430             # Description: helper function. add vchain to generator object
1431             ################################################################################
1432             sub bind_vchain
1433             {
1434 99     99 1 190 my $self =shift;
1435 99         156 my $vchain =shift;
1436 99         160 push(@{$self->{vchain_array}},$vchain);
  99         248  
1437 99         338 $self->{vchain_hash}
1438 99         187 ->{$#{$self->{vchain_array}}}=$vchain;
1439             }
1440              
1441              
1442             ################################################################################
1443             # sub bind_actual_vchain
1444             # Description: Postprocessing action.
1445             # At the end of each chain production, add actual value chain to the chain list
1446             # root structure, and afterwards reset actual_vchain to an empty hash
1447             #
1448             ################################################################################
1449             sub bind_actual_vchain
1450             {
1451 54     54 1 92590 my $self =shift;
1452 54 100       272 if ($self->{chain_type} eq 'INTEGER')
1453             {
1454 5         28 $self->vchain_integer_process();
1455 5         161 return;
1456             }
1457 49 100 100     366 if ((exists $self->{actual_vchain}->{chain_subtype})
1458             && ($self->{actual_vchain}->{chain_subtype} eq 'DATEWITHFRACTION'))
1459             {
1460 2         12 $self->vchain_date_fraction_process();
1461 2         64 return;
1462             }
1463 47 100       272 if ($self->{chain_type} eq 'FLOAT')
1464             {
1465 26         131 $self->vchain_float_process();
1466 26         811 return;
1467             }
1468 21         95 $self->bind_vchain($self->{actual_vchain});
1469 21         83 $self->reset_actual_vchain();
1470             }
1471              
1472             ################################################################################
1473             # sub add_value_column
1474             # Description:
1475             # add array of terms.
1476             #
1477             ################################################################################
1478             sub add_value_column
1479             {
1480 136     136 1 218 my $self = shift;
1481 136         185 my $tmp_value_column = shift;
1482 136         245 my $value_column = [];
1483 136         216 my $vcol_maxlength=0;
1484 136         228 my $ix=0;
1485 136         220 my $unique={};
1486 136         207 foreach my $value_term (@{$tmp_value_column})
  136         305  
1487             {
1488 787         1073 my $vterm_length=length($value_term);
1489 787 100 66     7564 if (exists $self->{ct_length} && defined $self->{ct_length} &&
    100 100        
1490             $self->{actual_vchain}->{vchain_length}+ $vterm_length>$self->{ct_length})
1491             {
1492 1         269 carp "Maximal length for type $self->{chain_type}($self->{ct_length}) "
1493             ."exceeded for \n$self->{vchain_text}\n"
1494             ."Element \'$value_term\' will be removed from output structures.\n"
1495             ."Please check your data creation rules\n";
1496 1         207 next;
1497             }
1498             elsif ($unique->{$value_term}++>0)
1499             {
1500 2         389 carp "Duplicate entry \'$value_term\' found while building up internal structures.\n"
1501             ."Element \'$value_term\' will be removed from output structures.\n"
1502             ."Please check your data creation rules\n";
1503 2         359 next;
1504             }
1505             else
1506             {
1507 784         864 push(@{$value_column},$value_term);
  784         1633  
1508 784 100       1496 $vcol_maxlength =($vterm_length>$vcol_maxlength?$vterm_length:$vcol_maxlength);
1509 784         1273 $ix++;
1510             }
1511             };
1512 136         423 $self->{actual_vchain}->{vchain_length}+=$vcol_maxlength;
1513 136 100       184 if ($#{$value_column}==-1)
  136         438  
1514             {
1515 1         5 return 1;
1516             }
1517              
1518 135 100       432 if (exists $self->{actual_vchain}->{vcol_count})
1519 53         169 {
1520            
1521 82         186 $self->{actual_vchain}->{vcol_count}++
1522             }
1523             else
1524             {$self->{actual_vchain}->{vcol_count}=0}
1525            
1526 135         1024 $self->{actual_vchain}->{vcol_hash}->{$self->{actual_vchain}->{vcol_count}}->{value_column} = $value_column;
1527             }
1528              
1529              
1530              
1531             ################################################################################
1532             # sub get_value_column_reverse
1533             # Description: fill array in place with complementary ascii chars
1534             #
1535             ################################################################################
1536             sub get_value_column_reverse {
1537 1     1 1 3 my $self = shift;
1538 1         3 my $value_column = shift;
1539 1         251 my @complement = map(chr,(0..255));
1540 1         13 my $hash={};
1541 1         3 $hash->{$_}++ foreach (@{$value_column});
  1         101  
1542 1         4 $value_column=[];
1543 1         3 foreach (@complement)
1544             {
1545 256 100       647 push(@$value_column,$_) unless $hash->{$_};
1546             }
1547 1         39 return $value_column;
1548             }
1549              
1550              
1551             ################################################################################
1552             # sub get_occupation_ratio
1553             # Description:
1554             # Based on input cardinality and degrees of freedom calculate
1555             # the ratio of array elements to give / total number of elements
1556             #
1557             ################################################################################
1558             sub set_occupation_ratio
1559             {
1560 54     54 1 91 my $self = shift;
1561 54         114 foreach my $actual_vchain (@{$self->{vchain_array}})
  54         128  
1562             {
1563 121         147 my $occupation_ratio = 0;
1564 121         473 $occupation_ratio =
1565             log($actual_vchain->{data_card}/$actual_vchain->{vchain_card})
1566             / ($actual_vchain->{vcol_count}+1);
1567 121         245 $occupation_ratio =exp($occupation_ratio);
1568 121         328 $actual_vchain->{vchain_occupation_ratio}= $occupation_ratio;
1569             }
1570             }
1571              
1572              
1573              
1574             ################################################################################
1575             # sub calculate_occupation_levels
1576             # Description:
1577             # based on input cardinality calculate occupation levels.
1578             #
1579             ################################################################################
1580             sub calculate_occupation_levels
1581             {
1582 54     54 1 87 my $self = shift;
1583 54         170 my $data_card = shift;
1584 54         156 $self->check_input_card($data_card);
1585 54         173 $self->set_occupation_ratio();
1586 54         99 foreach my $actual_vchain (@{$self->{vchain_array}})
  54         135  
1587             {
1588 121         187 my $vchain_occupation_ratio =$actual_vchain->{vchain_occupation_ratio};
1589 121         147 foreach (values %{$actual_vchain->{vcol_hash}})
  121         327  
1590             {
1591 568         594 my $vcol_degrees_of_freedom =$#{$_->{value_column}}+1;
  568         972  
1592 568 100       981 if ($vchain_occupation_ratio ==1)
1593 271         556 { $_->{occupation_level} = $vcol_degrees_of_freedom }
1594             else
1595             {
1596 297         716 $_->{occupation_level} =
1597             int($vchain_occupation_ratio*$vcol_degrees_of_freedom)+1;
1598             }
1599             }
1600             }
1601 54         110 return ;
1602             }
1603              
1604              
1605             ################################################################################
1606             # sub get_degrees_of_freedom
1607             # Description:
1608             # get maximal cardinality
1609             #
1610             ################################################################################
1611             sub get_degrees_of_freedom
1612             {
1613 29     29 1 26257 my $self = shift;
1614 29         68 my $weigthed_card=undef;
1615 29         74 foreach my $vchain_ref (@{$self->{vchain_array}})
  29         93  
1616             {
1617 66 50 33     435 confess " weigth undefined " unless defined $vchain_ref->{weigth} &&
1618             defined $vchain_ref->{vchain_card};
1619 66 50       194 if ($vchain_ref->{weigth} >0.0001)
1620             {
1621 66         236 $vchain_ref->{weigthed_card}=$vchain_ref->{vchain_card}/
1622             $vchain_ref->{weigth};
1623             }
1624             else
1625             {
1626 0         0 $vchain_ref->{weigthed_card}=10000
1627             }
1628 66 50       205 $vchain_ref->{weigthed_card}=1 if $vchain_ref->{weigthed_card}<1;
1629 66 100       210 $weigthed_card = $vchain_ref->{weigthed_card}
1630             unless defined $weigthed_card;
1631 66 100       235 $weigthed_card = $vchain_ref->{weigthed_card}
1632             if $weigthed_card > $vchain_ref->{weigthed_card} ;
1633             }
1634            
1635             # workaround to handle integers numbers converted to float and back
1636 29 100       145 if ( int($weigthed_card)+1-$weigthed_card <1e-9)
1637             {
1638 1         4 return int($weigthed_card)+1;
1639             }
1640 28         98 return int($weigthed_card);
1641             }
1642              
1643              
1644              
1645              
1646             ################################################################################
1647             # sub calculate_vchain_list_degrees_of_freedom
1648             # Description:
1649             # calculate maximal cardinality for a vchain
1650             #
1651             ################################################################################
1652             sub calculate_vchain_list_degrees_of_freedom
1653             {
1654 52     52 1 93 my $vchain_list = shift;
1655 52         89 my $card=0;
1656 52         103 foreach my $vchain_ref (@$vchain_list)
1657             {
1658 118         211 $vchain_ref->{vchain_card}=1;
1659 118         149 foreach my $vcol_ref (values %{$vchain_ref->{vcol_hash}})
  118         357  
1660 591         667 { $vchain_ref->{vchain_card}*=$#{$vcol_ref->{value_column}}+1 }
  591         1089  
1661 118         251 $card+=$vchain_ref->{vchain_card};
1662             }
1663 52         140 return $card;
1664             }
1665              
1666              
1667             ################################################################################
1668             # sub calculate_degrees_of_freedom
1669             # Description:
1670             # calculate maximal cardinality of the generation rules
1671             #
1672             ################################################################################
1673             sub calculate_degrees_of_freedom
1674             {
1675 29     29 1 54 my $self = shift;
1676 29         106 $self->{card}=
1677             calculate_vchain_list_degrees_of_freedom($self->{vchain_array});
1678 29         63 return $self->{card};
1679             }
1680              
1681              
1682             ################################################################################
1683             # sub calculate_weigth
1684             # Description:
1685             # normalize weigth so that total is 100%
1686             #
1687             ################################################################################
1688             sub calculate_weigth
1689             {
1690 29     29 1 52 my $self = shift;
1691 29         59 my $weigth=0.0;
1692 29         49 foreach my $vchain_ref (@{$self->{vchain_array}})
  29         91  
1693             {
1694 66         353 $weigth+= $vchain_ref->{weigth};
1695             }
1696 29         80 foreach my $vchain_ref (@{$self->{vchain_array}})
  29         89  
1697             {
1698 66         216 $vchain_ref->{weigth}/=$weigth
1699             }
1700             }
1701              
1702              
1703             ################################################################################
1704             # sub check_input_card
1705             # Description:
1706             # ensures that degrees of freedom >= input_card
1707             # generates a warning when input_card is bigger
1708             #
1709             ################################################################################
1710             sub check_input_card
1711             {
1712 54     54 1 95 my $self = shift;
1713 54         81 my $data_card = shift;
1714 54 100       206 if ($data_card > $self->{card})
1715             {
1716 2         433 carp "Input card ".$data_card." too big, maximal nr of ".
1717             "values is $self->{card}.\nReturn only ".
1718             $self->{card} ." values. \n";
1719 2         263 $data_card=$self->{card};
1720             }
1721              
1722 54         79 foreach my $vchain_ref (@{$self->{vchain_array}})
  54         166  
1723             {
1724 121         211 $vchain_ref->{data_card}=$data_card;
1725 121         199 $vchain_ref->{data_card}*=$vchain_ref->{weigth};
1726             # $vchain_ref->{data_card}=int($vchain_ref->{data_card});
1727             # $vchain_ref->{data_card}=1 if $vchain_ref->{data_card}==0;
1728 121 50       476 if (int($vchain_ref->{data_card}) >$vchain_ref->{vchain_card})
1729             {
1730 0         0 carp "Either input card ".$data_card." too big or vchain weigth ".
1731             "$vchain_ref->{weigth} too high.\nShould produce ".
1732             $vchain_ref->{data_card}." values, can't produce more than ".
1733             $vchain_ref->{vchain_card}." different values.\nReturn only ".
1734             $vchain_ref->{vchain_card} ." values. \n";
1735 0         0 $vchain_ref->{data_card}=$vchain_ref->{vchain_card};
1736             }
1737             }
1738             }
1739              
1740             ################################################################################
1741             # sub fisher_yates_shuffle
1742             # Description: create a randomized array order. From Perl Cookbook
1743             #
1744             ################################################################################
1745             # fisher_yates_shuffle( \@array ) : generate a random permutation
1746             # of @array in place
1747             sub fisher_yates_shuffle {
1748 54     54 1 87 my $array = shift;
1749 54         75 my $i;
1750 54         185 for ($i = @$array; --$i; ) {
1751 3799         5010 my $j = int rand ($i+1);
1752 3799 100       11013 next if $i == $j;
1753 3711         11904 @$array[$i,$j] = @$array[$j,$i];
1754             }
1755             }
1756              
1757              
1758              
1759             ################################################################################
1760             # sub is_valid
1761             # Description: check if generator structure was built up successfully
1762             #
1763             ################################################################################
1764             sub is_valid {
1765 29     29 1 61 my $self = shift;
1766 29 50       49 return undef if @{$self->{vchain_array}} ==0;
  29         140  
1767 29         125 1;
1768             }
1769              
1770              
1771              
1772             ################################################################################
1773             # sub get_data
1774             # Description:
1775             # get data
1776             #
1777             ################################################################################
1778             sub get_unique_data
1779             {
1780 54     54 1 37311 my $self = shift;
1781 54         142 my $data_card =shift;
1782 54         174 $self->calculate_occupation_levels($data_card);
1783 54         93 my $data =[];
1784 54         111 my $chain_type=$self->{chain_type};
1785 54         83 foreach my $actual_vchain (@{$self->{vchain_array}})
  54         128  
1786             {
1787 121         465 my $tmpdata =[''];
1788 121         304 foreach my $value_column_index (0..$actual_vchain->{vcol_count})
1789             {
1790 568         1290 my $value_column=$actual_vchain->{vcol_hash}->{$value_column_index};
1791 568         657 my @tmp_value_column_copy=@{$value_column->{value_column}};
  568         1824  
1792 568         784 my @value_column_array =();
1793 568         1392 while(@value_column_array<$value_column->{occupation_level})
1794             {
1795 1354         7346 my $rnd_index=int(rand(@tmp_value_column_copy));
1796 1354         7188 push(@value_column_array,splice(@tmp_value_column_copy,$rnd_index,1));
1797             }
1798 568         772 my $format=undef;
1799 568 100 100     3120 $format=
1800             $Data::Generate::vchain_type->{$chain_type}->{vcol_output_format}
1801             ->[$value_column_index]
1802             if ((exists $Data::Generate::vchain_type->{$chain_type})
1803             && (exists $Data::Generate::vchain_type
1804             ->{$chain_type}->{vcol_output_format}));
1805 568         1419 $tmpdata=vcol_chain($tmpdata, \@value_column_array,
1806             $actual_vchain->{data_card},$format);
1807              
1808             }
1809 121         1474 push(@$data,@$tmpdata);
1810             }
1811             # makes a random order
1812 54         187 fisher_yates_shuffle($data);
1813             # take away too much produced data
1814 54         200 shift(@$data) while(@$data>$data_card);
1815 54 100 100     408 map($_=&{$Data::Generate::vchain_type
  3189         7636  
1816             ->{$chain_type}->{output_format_fct}}($_),@$data)
1817             if ((exists $Data::Generate::vchain_type->{$chain_type})
1818             && (exists $Data::Generate::vchain_type
1819             ->{$chain_type}->{output_format_fct}));
1820 54 100       347 @$data = map(int($_),@$data) if $chain_type eq 'INTEGER';
1821 54         15306 @$data = sort(@$data);
1822 54         257 my $uniq=[];
1823 54         98 my $last='';
1824 54         88 my $duplicates=0;
1825 54         160 foreach my $item (@$data) {
1826 3836 50       8328 if ($last eq $item)
1827             {
1828 0         0 $duplicates++;
1829 0         0 next;
1830             }
1831 3836         4295 push(@$uniq, $item);
1832 3836         4199 $last=$item;
1833             }
1834 54 50       160 carp "$duplicates duplicates found while generating ouput values.\n"
1835             ."Check syntax of statements" if $duplicates>0;
1836 54         1303 return $uniq;
1837             }
1838              
1839              
1840             ################################################################################
1841             # sub vcol_chain
1842             # Description:
1843             # make a cross product of two value columns and concatenate the values.
1844             # if type is with formatted output prepare values with a pipe inbetween.
1845             #
1846             ################################################################################
1847             sub vcol_chain
1848             {
1849 568     568 1 611 my @original=@{shift()};
  568         2124  
1850 568         755 my @added =@{shift()};
  568         1294  
1851 568         759 my $card=shift;
1852 568         607 my $format=shift;
1853 568 100       1164 $format= "%s" unless defined $format;
1854 568         803 my @composed =();
1855 568         770 foreach my $ele (@added)
1856             {
1857            
1858 1258         1517 foreach my $e2 (@original)
1859             {
1860 9090         18575 push(@composed,$e2.sprintf($format,$ele));
1861 9090 50       16385 next unless defined $card;
1862 9090 100       22818 return \@composed if(@composed>=$card);
1863             }
1864             }
1865 175         860 return \@composed;
1866              
1867             };
1868              
1869              
1870              
1871              
1872              
1873              
1874             ################################################################################
1875             # sub parse
1876             # Description:
1877             # parse given text.
1878             # return either an error or a Data::Generate object
1879             #
1880             ################################################################################
1881             sub parse($)
1882             {
1883 29     29 1 40187 my ($text) = @_;
1884            
1885             # check that parser is up and running
1886 29 100       150 $Data::Generate::Parser=load_parser()
1887             unless (defined $Data::Generate::Parser);
1888              
1889              
1890             # create a new generator and set it as global for parse routines
1891 29         77 $Data::Generate::ACTUAL_VALUE_COLUMN=undef;
1892 29         50 $Data::Generate::VC_RANGE_REVERSE_FLAG=undef;
1893              
1894              
1895 29         174 $Data::Generate::current= Data::Generate->new($text);
1896 29         1152 $Data::Generate::Parser->start($text);
1897 29 50       7739 $Data::Generate::current->is_valid() or
1898             croak "Error in parsing, invalid generator for $text";
1899 29         127 $Data::Generate::current->calculate_weigth();
1900 29         119 $Data::Generate::current->calculate_degrees_of_freedom();
1901 29         123 return $Data::Generate::current;
1902             }
1903              
1904              
1905              
1906              
1907             1;
1908              
1909              
1910             __END__