| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# |
|
2
|
|
|
|
|
|
|
# This file is part of Soar-Production |
|
3
|
|
|
|
|
|
|
# |
|
4
|
|
|
|
|
|
|
# This software is copyright (c) 2012 by Nathan Glenn. |
|
5
|
|
|
|
|
|
|
# |
|
6
|
|
|
|
|
|
|
# This is free software; you can redistribute it and/or modify it under |
|
7
|
|
|
|
|
|
|
# the same terms as the Perl 5 programming language system itself. |
|
8
|
|
|
|
|
|
|
# |
|
9
|
|
|
|
|
|
|
package Soar::Production::Parser::PRDGrammar; |
|
10
|
|
|
|
|
|
|
# ABSTRACT: Parse::RecDescent grammar for Soar productions |
|
11
|
|
|
|
|
|
|
|
|
12
|
26
|
|
|
26
|
|
733
|
use strict; |
|
|
26
|
|
|
|
|
50
|
|
|
|
26
|
|
|
|
|
838
|
|
|
13
|
26
|
|
|
26
|
|
131
|
use warnings; |
|
|
26
|
|
|
|
|
49
|
|
|
|
26
|
|
|
|
|
3799
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION = '0.03'; # VERSION |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
#this grammar will return a parse tree of a production |
|
18
|
|
|
|
|
|
|
our $GRAMMAR = <<'EOGRAMMAR'; |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
parse: |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
(?: \s+ # Whitespace |
|
23
|
|
|
|
|
|
|
| (?:;\s*)?\# [^\n]* \n? # End of line comment |
|
24
|
|
|
|
|
|
|
) |
|
25
|
|
|
|
|
|
|
)*}> production /\Z/ |
|
26
|
|
|
|
|
|
|
{ |
|
27
|
|
|
|
|
|
|
$item[2] |
|
28
|
|
|
|
|
|
|
} |
|
29
|
|
|
|
|
|
|
#future work: can be sp or tp (normal or template production) |
|
30
|
|
|
|
|
|
|
production: /sp/ "{" beginning LHS "-->" RHS "}" |
|
31
|
|
|
|
|
|
|
{ |
|
32
|
|
|
|
|
|
|
my %return; |
|
33
|
|
|
|
|
|
|
@return{ keys %{$item[3]}} = values %{$item[3]}; |
|
34
|
|
|
|
|
|
|
$return{LHS} = $item{LHS}; |
|
35
|
|
|
|
|
|
|
$return{RHS} = $item{RHS}->{rhsActions}; |
|
36
|
|
|
|
|
|
|
\%return; |
|
37
|
|
|
|
|
|
|
} |
|
38
|
|
|
|
|
|
|
beginning: prodname documentation(?) flag(s?) |
|
39
|
|
|
|
|
|
|
{ |
|
40
|
|
|
|
|
|
|
{name => $item[1], doc => $item[2] ? $item[2][0] : undef, flags => $item[3]} |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
prodname: /[\dA-Za-z][\dA-Za-z\$%&*=>
|
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
#documentation can span many lines |
|
45
|
|
|
|
|
|
|
documentation: '"' /[^"]*/ms '"' |
|
46
|
|
|
|
|
|
|
{ |
|
47
|
|
|
|
|
|
|
$item[3] |
|
48
|
|
|
|
|
|
|
} |
|
49
|
|
|
|
|
|
|
flag: ':' /o-support|i-support|chunk|default|interrupt|template/ |
|
50
|
|
|
|
|
|
|
LHS: cond(s) |
|
51
|
|
|
|
|
|
|
{ |
|
52
|
|
|
|
|
|
|
{ conditions => $item[1] } |
|
53
|
|
|
|
|
|
|
} |
|
54
|
|
|
|
|
|
|
condType: "state" | "impasse" |
|
55
|
|
|
|
|
|
|
cond: |
|
56
|
|
|
|
|
|
|
positiveCond |
|
57
|
|
|
|
|
|
|
{ |
|
58
|
|
|
|
|
|
|
{ negative => 'no', condition => $item{positiveCond} } |
|
59
|
|
|
|
|
|
|
} |
|
60
|
|
|
|
|
|
|
| negativeCond |
|
61
|
|
|
|
|
|
|
{ |
|
62
|
|
|
|
|
|
|
{ negative => 'yes', condition => $item{negativeCond} } |
|
63
|
|
|
|
|
|
|
} |
|
64
|
|
|
|
|
|
|
negativeCond: "-" positiveCond |
|
65
|
|
|
|
|
|
|
positiveCond: condsForOneId |
|
66
|
|
|
|
|
|
|
{ |
|
67
|
|
|
|
|
|
|
$item{condsForOneId}; |
|
68
|
|
|
|
|
|
|
} |
|
69
|
|
|
|
|
|
|
| "{" cond(s) "}" |
|
70
|
|
|
|
|
|
|
{ |
|
71
|
|
|
|
|
|
|
{ 'conjunction' => $item[3] } |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
condsForOneId: "(" condType(?) idTest(?) attrValueTests(s?) ")" |
|
74
|
|
|
|
|
|
|
#only a state_imp_cond can be missing an idTest or attrValueTests |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
not defined $item[3] and ( |
|
77
|
|
|
|
|
|
|
not defined $item[4] or $#{$item[5]} == -1 |
|
78
|
|
|
|
|
|
|
) |
|
79
|
|
|
|
|
|
|
} > |
|
80
|
|
|
|
|
|
|
{ |
|
81
|
|
|
|
|
|
|
{ |
|
82
|
|
|
|
|
|
|
condType => ($#{$item[3]} != -1 ? $item[3][0] : undef), |
|
83
|
|
|
|
|
|
|
idTest => ($#{$item[4]} != -1 ? $item[4][0]->{test} : undef), |
|
84
|
|
|
|
|
|
|
attrValueTests => $item[5], |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
idTest: test |
|
88
|
|
|
|
|
|
|
{ |
|
89
|
|
|
|
|
|
|
{ test => $item{test} } |
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
attrValueTests: /-?/ attTest valueTest(s?) |
|
92
|
|
|
|
|
|
|
{ |
|
93
|
|
|
|
|
|
|
{ |
|
94
|
|
|
|
|
|
|
negative => ($item[1] ? 'yes' : 'no'), |
|
95
|
|
|
|
|
|
|
attrs => $item[2], |
|
96
|
|
|
|
|
|
|
values => $item[3], |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
attTest: "^" test(s /\./) |
|
100
|
|
|
|
|
|
|
valueTest: test /\+?/ |
|
101
|
|
|
|
|
|
|
{ |
|
102
|
|
|
|
|
|
|
{ |
|
103
|
|
|
|
|
|
|
test => $item{test}, |
|
104
|
|
|
|
|
|
|
'+' => ($item[2] ? 'yes' : 'no'), |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
} |
|
107
|
|
|
|
|
|
|
| condsForOneId /\+?/ |
|
108
|
|
|
|
|
|
|
{ |
|
109
|
|
|
|
|
|
|
{ |
|
110
|
|
|
|
|
|
|
conds => $item{condsForOneId}, |
|
111
|
|
|
|
|
|
|
'+' => ($item[2] ? 'yes' : 'no'), |
|
112
|
|
|
|
|
|
|
} |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
test: |
|
115
|
|
|
|
|
|
|
conjunctiveTest |
|
116
|
|
|
|
|
|
|
{ |
|
117
|
|
|
|
|
|
|
{ conjunctiveTest => $item{conjunctiveTest} } |
|
118
|
|
|
|
|
|
|
} |
|
119
|
|
|
|
|
|
|
| simpleTest |
|
120
|
|
|
|
|
|
|
{ |
|
121
|
|
|
|
|
|
|
{ simpleTest => $item{simpleTest} } |
|
122
|
|
|
|
|
|
|
} |
|
123
|
|
|
|
|
|
|
conjunctiveTest: "\{" simpleTest(s) "\}" |
|
124
|
|
|
|
|
|
|
{ |
|
125
|
|
|
|
|
|
|
$item[3] |
|
126
|
|
|
|
|
|
|
} |
|
127
|
|
|
|
|
|
|
simpleTest: |
|
128
|
|
|
|
|
|
|
disjunctionTest |
|
129
|
|
|
|
|
|
|
{ |
|
130
|
|
|
|
|
|
|
{ disjunctionTest => $item{disjunctionTest} } |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
| relationalTest |
|
133
|
|
|
|
|
|
|
{ |
|
134
|
|
|
|
|
|
|
{ relationTest => $item{relationalTest} } |
|
135
|
|
|
|
|
|
|
} |
|
136
|
|
|
|
|
|
|
| singleTest |
|
137
|
|
|
|
|
|
|
{ |
|
138
|
|
|
|
|
|
|
$item{singleTest} |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
disjunctionTest: /<<(?=\s)/ constant(s) />>/ #don't have to worry about look for whitespace on second one; if no space is there, the parser will think it's a string and fail. |
|
141
|
|
|
|
|
|
|
{ |
|
142
|
|
|
|
|
|
|
$item[3] |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
relationalTest: relation singleTest #note that I removed a (?) from relation, and added singleTest to simpleTest |
|
145
|
|
|
|
|
|
|
{ |
|
146
|
|
|
|
|
|
|
{ relation => ($item{relation} || undef), test => $item{singleTest} } |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
# /<(?=\s)/ ensures we don't match the beginning of a variable |
|
149
|
|
|
|
|
|
|
relation: "<=>" | "<>" | "<=" | ">=" | ">" | /<(?=\s)/ | "=" |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
singleTest: |
|
152
|
|
|
|
|
|
|
variable |
|
153
|
|
|
|
|
|
|
{ |
|
154
|
|
|
|
|
|
|
$item{variable} |
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
| constant |
|
157
|
|
|
|
|
|
|
{ |
|
158
|
|
|
|
|
|
|
$item{constant} |
|
159
|
|
|
|
|
|
|
} |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
#change skip so we can't have |
|
162
|
|
|
|
|
|
|
variable: /<[A-Za-z0-9\$%&*+\/:=?_<>-]+(?)>/ |
|
163
|
|
|
|
|
|
|
{ |
|
164
|
|
|
|
|
|
|
$item[1] =~ s/^<(.*)>$/$1/; |
|
165
|
|
|
|
|
|
|
{variable => $item[1] } |
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
RHS: rhsAction(s?) |
|
169
|
|
|
|
|
|
|
{ |
|
170
|
|
|
|
|
|
|
{ rhsActions => $item[1] } |
|
171
|
|
|
|
|
|
|
} |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
rhsAction: |
|
174
|
|
|
|
|
|
|
funcCall |
|
175
|
|
|
|
|
|
|
{ |
|
176
|
|
|
|
|
|
|
{ funcCall => $item{funcCall} } |
|
177
|
|
|
|
|
|
|
} |
|
178
|
|
|
|
|
|
|
| "(" variable attrValueMake(s) ")" |
|
179
|
|
|
|
|
|
|
{ |
|
180
|
|
|
|
|
|
|
{ variable => $item{variable}->{variable}, attrValueMake => $item[3] } |
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
funcCall: "(" funcName rhsValue(s?) ")" |
|
184
|
|
|
|
|
|
|
{ |
|
185
|
|
|
|
|
|
|
{ function => $item{funcName}, args => $item[4] } |
|
186
|
|
|
|
|
|
|
} |
|
187
|
|
|
|
|
|
|
funcName: "+" | "-" | "*" | "/" | symConstant |
|
188
|
|
|
|
|
|
|
rhsValue: variable | constant | "(crlf)" | funcCall |
|
189
|
|
|
|
|
|
|
attrValueMake: valueMake(s) |
|
190
|
|
|
|
|
|
|
{ |
|
191
|
|
|
|
|
|
|
{ attr => $item[1], valueMake => $item[2] } |
|
192
|
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
attr: "^" variableOrSymConstant |
|
194
|
|
|
|
|
|
|
variableOrSymConstant: variable | symConstant |
|
195
|
|
|
|
|
|
|
valueMake: rhsValue preferenceSpecifier(s?) |
|
196
|
|
|
|
|
|
|
{ |
|
197
|
|
|
|
|
|
|
#add an acceptable preference if no preference is specified |
|
198
|
|
|
|
|
|
|
my $preferences = $item[2]; |
|
199
|
|
|
|
|
|
|
if($#$preferences == -1){ |
|
200
|
|
|
|
|
|
|
$preferences = [{ |
|
201
|
|
|
|
|
|
|
'value' => '+', |
|
202
|
|
|
|
|
|
|
'type' => 'unary' |
|
203
|
|
|
|
|
|
|
}]; |
|
204
|
|
|
|
|
|
|
} |
|
205
|
|
|
|
|
|
|
{ rhsValue => $item{rhsValue}, preferences => $preferences } |
|
206
|
|
|
|
|
|
|
} |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
preferenceSpecifier: |
|
209
|
|
|
|
|
|
|
unaryOrBinaryPreference rhsValue comma(?) |
|
210
|
|
|
|
|
|
|
{ |
|
211
|
|
|
|
|
|
|
{ type => 'binary', value => $item{unaryOrBinaryPreference}, compareTo => $item{rhsValue} } |
|
212
|
|
|
|
|
|
|
} |
|
213
|
|
|
|
|
|
|
| unaryPreference comma(?) |
|
214
|
|
|
|
|
|
|
{ |
|
215
|
|
|
|
|
|
|
{ type => 'unary', value => $item{unaryPreference} }; |
|
216
|
|
|
|
|
|
|
} |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
comma: "," |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
unaryPreference: "+" | "-" | "!" | "~" | "@" | unaryOrBinaryPreference |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
#negative lookahead necessary to prevent matching as two specifiers and a constant |
|
223
|
|
|
|
|
|
|
unaryOrBinaryPreference: ">" | ...!variable "<" | "=" | "&" |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
#put float and int first, since symConstant can technically match the same values. |
|
226
|
|
|
|
|
|
|
constant: |
|
227
|
|
|
|
|
|
|
floatConstant |
|
228
|
|
|
|
|
|
|
{ |
|
229
|
|
|
|
|
|
|
{ constant => $item{floatConstant}, type => 'float' } |
|
230
|
|
|
|
|
|
|
} |
|
231
|
|
|
|
|
|
|
| intConstant |
|
232
|
|
|
|
|
|
|
{ |
|
233
|
|
|
|
|
|
|
{ constant => $item{intConstant}, type => 'int' } |
|
234
|
|
|
|
|
|
|
} |
|
235
|
|
|
|
|
|
|
| symConstant |
|
236
|
|
|
|
|
|
|
{ |
|
237
|
|
|
|
|
|
|
{ constant => $item{symConstant}, type => 'sym' } |
|
238
|
|
|
|
|
|
|
} |
|
239
|
|
|
|
|
|
|
symConstant: string { $item{string} } | quoted { $item{quoted} } |
|
240
|
|
|
|
|
|
|
string: /[A-Za-z0-9\$%&*+\/:=?_><-]+/ |
|
241
|
|
|
|
|
|
|
$/} > #reject if we've actually found a variable |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
$item[1] =~ /^ [+!~><=-]+ $/x and |
|
244
|
|
|
|
|
|
|
$item[1] !~ /^ (?: >< | [<>]{3,}) $/x |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
} |
|
247
|
|
|
|
|
|
|
> #reject if the name contains only preference characters |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# "" look like typos. Could have missed a pointy brace. |
|
250
|
|
|
|
|
|
|
if( $item[1] =~ /^<.*|.*>$/ ){ |
|
251
|
|
|
|
|
|
|
use Carp; |
|
252
|
|
|
|
|
|
|
carp "Suspicious string constant: \"$item[1]\". Did you mean to use a variable or disjunction?"; |
|
253
|
|
|
|
|
|
|
} |
|
254
|
|
|
|
|
|
|
}> |
|
255
|
|
|
|
|
|
|
{ |
|
256
|
|
|
|
|
|
|
# "" look like typos. Could have missed a pointy brace. Convert to quoted like Soar does. |
|
257
|
|
|
|
|
|
|
if( $item[1] =~ /^<.*|.*>$/ ){ |
|
258
|
|
|
|
|
|
|
$return = { type => 'quoted', value => $item[1] }; |
|
259
|
|
|
|
|
|
|
}else{ |
|
260
|
|
|
|
|
|
|
$return = { type => 'string', value => $item[1] }; |
|
261
|
|
|
|
|
|
|
} |
|
262
|
|
|
|
|
|
|
} |
|
263
|
|
|
|
|
|
|
#TODO: note that in Soar, || is ignored and treated like . |
|
264
|
|
|
|
|
|
|
quoted: /\|(?:\\[|]|[^|])*\|/ |
|
265
|
|
|
|
|
|
|
{ |
|
266
|
|
|
|
|
|
|
#remove leading and trailing vertical bar |
|
267
|
|
|
|
|
|
|
$item[1] =~ s{^\|}{}; |
|
268
|
|
|
|
|
|
|
$item[1] =~ s{\|$}{}; |
|
269
|
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
#unescape other vertical bars |
|
271
|
|
|
|
|
|
|
$item[1] =~ s{\\\|}{|}g; |
|
272
|
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
{ type => 'quoted', value => $item[1] } |
|
274
|
|
|
|
|
|
|
} |
|
275
|
|
|
|
|
|
|
intConstant: /-?[0-9]+/ |
|
276
|
|
|
|
|
|
|
floatConstant: |
|
277
|
|
|
|
|
|
|
scientific { $item{scientific} } |
|
278
|
|
|
|
|
|
|
| normal { $item{normal} } |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
#strangely enough, the section after the period is optional; '1.' is legal. |
|
281
|
|
|
|
|
|
|
normal: /^[-+]?[0-9]*\.[0-9]*/ |
|
282
|
|
|
|
|
|
|
scientific: /[+-]?[0-9]\.[0-9]+[eE][-+]?[0-9]+/ |
|
283
|
|
|
|
|
|
|
EOGRAMMAR |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
1; |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
__END__ |