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__ |