| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# $Revision: #3 $$Date: 2005/08/31 $$Author: jd150722 $ |
|
2
|
|
|
|
|
|
|
###################################################################### |
|
3
|
|
|
|
|
|
|
# |
|
4
|
|
|
|
|
|
|
# This program is Copyright 2003-2005 by Jeff Dutton. |
|
5
|
|
|
|
|
|
|
# |
|
6
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or modify |
|
7
|
|
|
|
|
|
|
# it under the terms of either the GNU General Public License or the |
|
8
|
|
|
|
|
|
|
# Perl Artistic License. |
|
9
|
|
|
|
|
|
|
# |
|
10
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be useful, |
|
11
|
|
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12
|
|
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13
|
|
|
|
|
|
|
# GNU General Public License for more details. |
|
14
|
|
|
|
|
|
|
# |
|
15
|
|
|
|
|
|
|
# If you do not have a copy of the GNU General Public License write to |
|
16
|
|
|
|
|
|
|
# the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, |
|
17
|
|
|
|
|
|
|
# MA 02139, USA. |
|
18
|
|
|
|
|
|
|
###################################################################### |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
package Parse::RandGen::Grammar; |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
require 5.006_001; |
|
23
|
4
|
|
|
4
|
|
20
|
use Carp; |
|
|
4
|
|
|
|
|
8
|
|
|
|
4
|
|
|
|
|
240
|
|
|
24
|
4
|
|
|
4
|
|
22
|
use Data::Dumper; |
|
|
4
|
|
|
|
|
10
|
|
|
|
4
|
|
|
|
|
178
|
|
|
25
|
4
|
|
|
4
|
|
24
|
use Parse::RandGen qw($Debug); |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
436
|
|
|
26
|
4
|
|
|
4
|
|
21
|
use strict; |
|
|
4
|
|
|
|
|
6
|
|
|
|
4
|
|
|
|
|
208
|
|
|
27
|
4
|
|
|
4
|
|
22
|
use vars qw($Debug); |
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
5490
|
|
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
###################################################################### |
|
30
|
|
|
|
|
|
|
#### Creators |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub new { |
|
33
|
1
|
|
|
1
|
1
|
17
|
my $class = shift; |
|
34
|
1
|
|
|
|
|
7
|
my $self = { |
|
35
|
|
|
|
|
|
|
_name => undef, # Name of the grammar |
|
36
|
|
|
|
|
|
|
_rules => { }, # Rules of the grammar |
|
37
|
|
|
|
|
|
|
_examples => { }, # Examples for various rules in the grammar |
|
38
|
|
|
|
|
|
|
#@_, |
|
39
|
|
|
|
|
|
|
}; |
|
40
|
1
|
|
33
|
|
|
8
|
bless $self, ref($class)||$class; |
|
41
|
|
|
|
|
|
|
|
|
42
|
1
|
50
|
|
|
|
10
|
$self->{_name} = shift or confess("%Error: Cannot call new without a name for the new grammer (only required argument)!"); |
|
43
|
1
|
|
|
|
|
3
|
return($self); |
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
###################################################################### |
|
47
|
|
|
|
|
|
|
#### Methods |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# Add Rules to the Grammar |
|
50
|
|
|
|
|
|
|
sub addRule { |
|
51
|
1
|
|
|
1
|
0
|
2
|
my $expType = "Parse::RandGen::Rule"; |
|
52
|
1
|
50
|
|
|
|
4
|
my $self = shift or confess("%Error: Cannot call without a valid object!"); |
|
53
|
1
|
50
|
|
|
|
4
|
my $rule = shift or confess("%Error: addRule takes a required $expType object!"); |
|
54
|
1
|
50
|
|
|
|
5
|
confess("%Error: Passed a ".ref($rule)." argument instead of a $expType reference argument!") unless (ref($rule) eq $expType); |
|
55
|
1
|
50
|
|
|
|
6
|
confess("%Error: Overwriting the existing rule for ", $rule->name(), "!") if exists($self->{_rules}{$rule->name()}); |
|
56
|
1
|
50
|
33
|
|
|
5
|
confess("%Error: Passed a Rule that already belongs to a different Grammar object!\n") if (defined($rule->grammar()) && ($rule->grammar() != $self)); |
|
57
|
1
|
|
|
|
|
5
|
$self->{_rules}{$rule->name()} = $rule; # Save the rule in the _rule hash |
|
58
|
1
|
|
|
|
|
3
|
$rule->{_grammar} = $self; # Set the rule's grammar to self |
|
59
|
|
|
|
|
|
|
} |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
# Add examples for a particular Rule to the Grammar |
|
62
|
|
|
|
|
|
|
sub addExamples { |
|
63
|
0
|
0
|
|
0
|
0
|
0
|
my $self = shift or confess("%Error: Cannot call without a valid object!"); |
|
64
|
0
|
0
|
|
|
|
0
|
my $ruleName = shift or confess("%Error: Cannot call without a rule name!"); |
|
65
|
0
|
0
|
|
|
|
0
|
(ref($ruleName) eq "") or confess("%Error: Argument given for a rule name is actually a ".ref($ruleName)." reference!"); |
|
66
|
0
|
0
|
|
|
|
0
|
($self->rule($ruleName)) or confess("%Error: Cannot find the $ruleName rule on this grammar!"); |
|
67
|
0
|
|
|
|
|
0
|
my @examples = @_; |
|
68
|
|
|
|
|
|
|
|
|
69
|
0
|
0
|
|
|
|
0
|
if (!defined($self->{_examples}{$ruleName})) { |
|
70
|
0
|
|
|
|
|
0
|
$self->{_examples}{$ruleName} = [ ]; # List of examples for the given rule |
|
71
|
|
|
|
|
|
|
} |
|
72
|
0
|
|
|
|
|
0
|
my $exList = $self->{_examples}{$ruleName}; |
|
73
|
0
|
|
|
|
|
0
|
foreach my $example (@examples) { |
|
74
|
0
|
0
|
|
|
|
0
|
(ref($example) eq "HASH") or confess("%Error: Example argument should be a HASH reference with \"stat\" and \"val\" entries, but is actually a ".ref($example)." reference!"); |
|
75
|
0
|
0
|
0
|
|
|
0
|
(defined($example->{stat}) && defined($example->{val})) or confess("%Error: Example hash does not contain both \"stat\" and \"val\" entries!"); |
|
76
|
0
|
|
|
|
|
0
|
push @$exList, $example; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
} |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# Check the Grammar for completeness/errors |
|
81
|
|
|
|
|
|
|
sub check { |
|
82
|
0
|
0
|
|
0
|
0
|
0
|
my $self = shift or confess("%Error: Cannot call without a valid object!"); |
|
83
|
0
|
|
|
|
|
0
|
my $grammarName = $self->name(); |
|
84
|
|
|
|
|
|
|
|
|
85
|
0
|
|
|
|
|
0
|
my $err = ""; |
|
86
|
0
|
|
|
|
|
0
|
foreach my $ruleName (keys %{$self->{_rules}}) { |
|
|
0
|
|
|
|
|
0
|
|
|
87
|
0
|
|
|
|
|
0
|
my $rule = $self->rule($ruleName); |
|
88
|
0
|
|
|
|
|
0
|
$err .= $rule->check(); |
|
89
|
|
|
|
|
|
|
} |
|
90
|
0
|
|
|
|
|
0
|
return $err; |
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
# Dump the Grammar |
|
94
|
|
|
|
|
|
|
sub dump { |
|
95
|
0
|
0
|
|
0
|
1
|
0
|
my $self = shift or confess("%Error: Cannot call without a valid object!"); |
|
96
|
0
|
|
|
|
|
0
|
my $output = ""; |
|
97
|
0
|
0
|
|
|
|
0
|
if ($Debug) { |
|
98
|
0
|
|
|
|
|
0
|
my $d = Data::Dumper->new([$self]); |
|
99
|
0
|
|
|
|
|
0
|
$d->Terse(1); |
|
100
|
0
|
|
|
|
|
0
|
$output .= $self->name() . " = " . $d->Dump(); |
|
101
|
|
|
|
|
|
|
} else { |
|
102
|
0
|
|
|
|
|
0
|
$output .= "#" . $self->name() . " Grammar specification:\n"; |
|
103
|
|
|
|
|
|
|
#$output .= "\n"; |
|
104
|
0
|
|
|
|
|
0
|
my @ruleNames = sort keys %{$self->{_rules}}; |
|
|
0
|
|
|
|
|
0
|
|
|
105
|
0
|
|
|
|
|
0
|
foreach my $ruleName (@ruleNames) { |
|
106
|
0
|
|
|
|
|
0
|
$output .= $self->rule($ruleName)->dump(); |
|
107
|
|
|
|
|
|
|
} |
|
108
|
0
|
0
|
|
|
|
0
|
$output .= "# No rules defined...\n" if ($#ruleNames < 0); |
|
109
|
|
|
|
|
|
|
} |
|
110
|
0
|
|
|
|
|
0
|
return $output; |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
###################################################################### |
|
114
|
|
|
|
|
|
|
#### Accessors |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub name { |
|
117
|
0
|
0
|
|
0
|
1
|
0
|
my $self = shift or confess("%Error: Cannot call name() without a valid object!"); |
|
118
|
0
|
|
|
|
|
0
|
return $self->{_name}; |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub rule { # Access the named rule (no side effects: undef is returned if the rule is not found) |
|
122
|
0
|
0
|
|
0
|
1
|
0
|
my $self = shift or confess("%Error: Cannot call rule() without a valid object!"); |
|
123
|
0
|
0
|
|
|
|
0
|
my $name = shift or confess("%Error: Cannot call rule() without the name of the Rule to find!"); |
|
124
|
0
|
0
|
0
|
|
|
0
|
if (exists($self->{_rules}{$name}) && !defined($self->{_rules}{$name})) { die "Grammar has a rule \"$name\", which references an undefined Rule object!\n"; } |
|
|
0
|
|
|
|
|
0
|
|
|
125
|
0
|
0
|
|
|
|
0
|
my $rule = $self->{_rules}{$name} if exists($self->{_rules}{$name}); |
|
126
|
0
|
|
|
|
|
0
|
return $rule; |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub defineRule { # Access the named rule (if it does not exist, create the rule) |
|
130
|
1
|
50
|
|
1
|
1
|
15
|
my $self = shift or confess("%Error: Cannot call defineRule() without a valid object!"); |
|
131
|
1
|
50
|
|
|
|
4
|
my $name = shift or confess("%Error: Cannot call defineRule() without the name of the Rule to find!"); |
|
132
|
1
|
50
|
33
|
|
|
7
|
exists($self->{_rules}{$name}) and not defined($self->{_rules}{$name}) and die ($self->name() . " Grammar has a rule \"$name\", which references an undefined Rule object!\n"); |
|
133
|
1
|
50
|
|
|
|
5
|
exists($self->{_rules}{$name}) and confess($self->name() . "Grammar already has a definition for the \"$name\" rule!\n"); |
|
134
|
1
|
50
|
|
|
|
5
|
if (!exists($self->{_rules}{$name})) { |
|
135
|
1
|
|
|
|
|
11
|
$self->addRule(Parse::RandGen::Rule->new($name)); |
|
136
|
|
|
|
|
|
|
} |
|
137
|
1
|
50
|
|
|
|
5
|
my $rule = $self->{_rules}{$name} or die "%Error: Failed to create the \"$name\" rule!"; |
|
138
|
1
|
|
|
|
|
11
|
return $rule; |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
sub ruleNames { |
|
142
|
0
|
0
|
|
0
|
0
|
|
my $self = shift or confess("%Error: Cannot call rules() without a valid object!"); |
|
143
|
0
|
|
|
|
|
|
return (sort keys %{$self->{_rules}}); |
|
|
0
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub examples { |
|
147
|
0
|
0
|
|
0
|
0
|
|
my $self = shift or confess("%Error: Cannot call without a valid object!"); |
|
148
|
0
|
0
|
|
|
|
|
my $ruleName = shift or confess("%Error: Cannot call without a rule name!"); |
|
149
|
0
|
0
|
|
|
|
|
($self->rule($ruleName)) or confess("%Error: Cannot find the $ruleName rule on this grammar!"); |
|
150
|
0
|
|
|
|
|
|
my @examples = ( ); |
|
151
|
|
|
|
|
|
|
|
|
152
|
0
|
0
|
|
|
|
|
if (defined($self->{_examples}{$ruleName})) { |
|
153
|
0
|
|
|
|
|
|
@examples = @{$self->{_examples}{$ruleName}}; |
|
|
0
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
} |
|
155
|
|
|
|
|
|
|
|
|
156
|
0
|
|
|
|
|
|
return @examples; |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
###################################################################### |
|
160
|
|
|
|
|
|
|
#### Package return |
|
161
|
|
|
|
|
|
|
1; |
|
162
|
|
|
|
|
|
|
__END__ |