1 ''' @file apg_py/api/rule_attributes.py
2 @brief Compute the rule attributes for all rules.
11 '''Simple class for attribute data for each rule.'''
13 def __init__(self, name='dummy', type=id.ATTR_N, group=-1):
15 @param name The name of the rule this attribute applies to.
16 @param type The identifier of the rule's recursive type.
17 @param group The group number if the type is
18 mutually-recursive (ATTR_MR),
36 '''Reset all attributes to false.'''
39 self.
rightright =
False
40 self.
emptyempty =
False
48 '''Create a duplicate attribute object from the present one.
49 @returns Returns new attribute object identical to the present one.
52 cpy.left = self.
leftleft
53 cpy.nested = self.
nestednested
54 cpy.right = self.
rightright
55 cpy.empty = self.
emptyempty
56 cpy.finite = self.
finitefinite
57 cpy.cyclic = self.
cycliccyclic
58 cpy.leaf = self.
leafleaf
59 cpy.is_open = self.
is_openis_open
61 cpy.name = self.
namename
62 cpy.lower = self.
lowerlower
63 cpy.type = self.
typetype
64 cpy.group = self.
groupgroup
68 '''Copy a given attribute into the present attribute.
69 @param cpy The attribute to copy.
71 self.
leftleft = cpy.left
72 self.
nestednested = cpy.nested
73 self.
rightright = cpy.right
74 self.
emptyempty = cpy.empty
75 self.
finitefinite = cpy.finite
76 self.
cycliccyclic = cpy.cyclic
77 self.
leafleaf = cpy.leaf
78 self.
is_openis_open = cpy.is_open
80 self.
namename = cpy.name
81 self.
lowerlower = cpy.lower
82 self.
typetype = cpy.type
83 self.
groupgroup = cpy.group
87 '''Compute the recursive and non-recursive attributes for each rule.
88 @param rules The list of rules.
89 @param rule_deps The rule dependencies previously computed
90 (see @ref rule_dependencies.py)
91 @returns Returns the rule attributes and any errors as a dictionary
92 {'errors': errors, 'attributes': attrs}
95 def op_eval(opcodes, op_index):
96 func = switch.get(opcodes[op_index][
'type'])
99 'op_eval: unrecognized opcode type',
100 opcodes[op_index][
'type'])
101 return func(opcodes, op_index)
103 def op_alt(opcodes, op_index):
105 op = opcodes[op_index]
106 op_range = range(
len(op[
'children']))
109 child_attrs.append(
Attr())
113 child_attrs[i] = op_eval(opcodes, op[
'children'][i])
117 for attr
in child_attrs:
121 attr_op.nested =
True
125 attr_op.cyclic =
True
129 attr_op.finite =
True
132 def is_recursive(attr):
133 if(attr.left
or attr.nested
or attr.right
or attr.cyclic):
137 def is_cat_nested(attrs):
138 children =
len(attrs)
146 for i
in range(children):
148 if(attri.right
and not attri.leaf):
149 for j
in range(i + 1, children):
151 if(
not attrj.empty
and not attrj.right
152 and not attrj.cyclic):
157 for i
in range(children - 1, -1, -1):
159 if(attri.right
and not attri.leaf):
160 for j
in range(i - 1, -1, -1):
162 if(
not attrj.empty
and not attrj.left
163 and not attrj.cyclic):
168 for i
in range(children):
170 if(
not attr.empty
and not is_recursive(attri)):
171 for j
in range(i + 1, children):
172 if(is_recursive(attrs[j])):
173 for k
in range(j + 1, children):
176 and not is_recursive(attrk)):
182 def is_cat_cyclic(attrs):
189 def is_cat_left(attrs):
199 def is_cat_right(attrs):
201 for i
in range(
len(attrs) - 1, -1, -1):
204 if(
not attrs[i].empty):
209 def is_cat_empty(attrs):
216 def is_cat_finite(attrs):
223 def op_cat(opcodes, op_index):
225 op = opcodes[op_index]
226 op_range = range(
len(op[
'children']))
229 child_attrs.append(
Attr())
233 child_attrs[i] = op_eval(opcodes, op[
'children'][i])
237 attr_op.left = is_cat_left(child_attrs)
238 attr_op.nested = is_cat_nested(child_attrs)
239 attr_op.right = is_cat_right(child_attrs)
240 attr_op.cyclic = is_cat_cyclic(child_attrs)
241 attr_op.empty = is_cat_empty(child_attrs)
242 attr_op.finite = is_cat_finite(child_attrs)
245 def op_rep(opcodes, op_index):
246 attr_op = op_eval(opcodes, op_index + 1)
247 if(opcodes[op_index][
'min'] == 0):
249 attr_op.finite =
True
252 def op_rnm(opcodes, op_index):
253 index = opcodes[op_index][
'index']
255 return working_attrs[index].dup()
257 def op_bkr(opcodes, op_index):
259 bkr_op = opcodes[op_index]
260 if(bkr_op[
'is_udt']):
261 attr_op.empty = bkr_op[
'empty']
262 attr_op.finite =
True
265 index = bkr_op[
'index']
267 attr_op.copy(working_attrs[index])
271 attr_op.nested =
False
272 attr_op.right =
False
273 attr_op.cyclic =
False
276 def op_and(opcodes, op_index):
277 attr_op = op_eval(opcodes, op_index + 1)
281 def op_tls(opcodes, op_index):
283 attr_op.empty =
len(opcodes[op_index][
'string']) == 0
284 attr_op.finite =
True
285 attr_op.cyclic =
False
288 def op_tbs(opcodes, op_index):
290 attr_op.empty =
False
291 attr_op.finite =
True
292 attr_op.cyclic =
False
295 def op_udt(opcodes, op_index):
297 attr_op.empty = opcodes[op_index][
'empty']
298 attr_op.finite =
True
299 attr_op.cyclic =
False
302 def op_anchor(opcodes, op_index):
305 attr_op.finite =
True
306 attr_op.cyclic =
False
325 def rule_eval(rule_index):
326 attri = working_attrs[rule_index]
327 if(attri.is_complete):
329 if(
not attri.is_open):
332 attr_op = op_eval(rules[rule_index][
'opcodes'], 0)
333 attri.left = attr_op.left
334 attri.nested = attr_op.nested
335 attri.right = attr_op.right
336 attri.cyclic = attr_op.cyclic
337 attri.finite = attr_op.finite
338 attri.empty = attr_op.empty
340 attri.is_open =
False
341 attri.is_complete =
True
344 if(rule_index == start_rule):
358 rule_count =
len(rules)
359 rule_range = range(rule_count)
366 rule_deps[i][
'recursive_type'],
367 rule_deps[i][
'group_no']))
368 working_attrs.append(
371 rule_deps[i][
'recursive_type'],
372 rule_deps[i][
'group_no']))
376 for attr
in working_attrs:
380 attrs[i].copy(working_attrs[i])
388 errors.append({
'line': rule[
'line'],
390 'msg':
'rule ' + rule[
'name'] +
' is cyclic'})
392 errors.append({
'line': rule[
'line'],
394 'msg':
'rule ' + rule[
'name'] +
395 ' is left recrusive'})
399 'line': rule[
'line'],
401 'msg':
'rule ' + rule[
'name'] +
402 ' only matches infinte strings'})
405 return {
'errors': errors,
'attributes': attrs}
409 '''Display all rule attributes.
410 @param attrs_arg The attributes to display.
411 @param mode The display mode
412 - 'index' Display attributes of rules in the order
413 they appear in the grammar syntax.
414 - 'type' Display attributes grouped by recursive type,
415 listed alphabetically within each type.
416 - 'alpha' Display attributes alphabetically by rule name.
417 @returns Returns a string of the display.
429 for attr
in attrs_arg:
430 attrs.append(attr.dup())
432 attrs.sort(key=sort_alpha)
433 attrs.sort(key=sort_type)
434 attrs.sort(key=sort_group)
435 elif(mode ==
'alpha'):
436 attrs.sort(key=sort_alpha)
438 fmt =
'%6s: %6s: %6s: %6s: %6s: %6s: %6s: %6s: %s\n'
440 display += (fmt % (
'left',
'nested',
441 'right',
'cyclic',
'finite',
451 def display_type(val):
452 if(val == id.ATTR_N):
454 if(val == id.ATTR_R):
456 if(val == id.ATTR_MR):
460 left = yes_or_no(attr.left)
461 nested = yes_or_no(attr.nested)
462 right = yes_or_no(attr.right)
463 cyclic = yes_or_no(attr.cyclic)
464 finite = yes_or_no(attr.finite)
465 empty = yes_or_no(attr.empty)
466 type = display_type(attr.type)
467 if(attr.type == id.ATTR_N
or attr.type == id.ATTR_R):
470 group = str(attr.group)
471 if(attr.type == id.ATTR_MR):
472 group = str(attr.group)
473 display += (fmt % (left, nested, right, cyclic,
474 finite, empty, type, group, attr.name))
Simple class for attribute data for each rule.
def reset(self)
Reset all attributes to false.
def dup(self)
Create a duplicate attribute object from the present one.
def __init__(self, name='dummy', type=id.ATTR_N, group=-1)
Attr constructor.
def copy(self, cpy)
Copy a given attribute into the present attribute.
def display_rule_attributes(attrs_arg, mode='index')
Display all rule attributes.
def rule_attributes(rules, rule_deps)
Compute the recursive and non-recursive attributes for each rule.