Help improve program for parsing simple rules

Aaron Brady castironpi at gmail.com
Thu Apr 16 21:59:06 CEST 2009


On Apr 16, 10:57 am, prueba... at latinmail.com wrote:
> Another interesting task for those that are looking for some
> interesting problem:
> I inherited some rule system that checks for programmers program
> outputs that to be ported: given some simple rules and the values it
> has to determine if the program is still working correctly and give
> the details of what the values are. If you have a better idea of how
> to do this kind of parsing please chime in. I am using tokenize but
> that might be more complex than it needs to be. This is what I have
> come up so far:
>
> rules=[
>          '( A - B ) = 0',
>          '(A + B + C + D + E + F + G + H + I) = J',
>          '(A + B + C + D + E + F + G + H) = I',
>          '(A + B + C + D + E + F) = G',
>          '(A + B + C + D + E) = (F + G + H + I + J)',
>          '(A + B + C + D + E) = (F + G + H + I)',
>          '(A + B + C + D + E) = F',
>          '(A + B + C + D) = (E + F + G + H)',
>          '(A + B + C) = (D + E + F)',
>          '(A + B) = (C + D + E + F)',
>          '(A + B) = (C + D)',
>          '(A + B) = (C - D + E - F - G + H + I + J)',
>          '(A + B) = C',
>          '(A + B) = 0',
>          '(A+B+C+D+E) = (F+G+H+I+J)',
>          '(A+B+C+D) = (E+F+G+H)',
>          '(A+B+C+D)=(E+F+G+H)',
>          '(A+B+C)=(D+E+F)',
>          '(A+B)=(C+D)',
>          '(A+B)=C',
>          '(A-B)=C',
>          '(A/(B+C))',
>          '(G + H) = I',
>          '-0.99 LE ((A+B+C)-(D+E+F+G)) LE 0.99',
>          '-0.99 LE (A-(B+C)) LE 0.99',
>          '-1000.00 LE A LE 0.00',
snip
> def main():
>     for cur_rule in rules[20:26]:
>         tokens=get_tokens(cur_rule)
>         normal=replace_comps(tokens,COMP_REPLACERS)
>         subst=replace_names(normal,vars_)
>         groups=split_seccions(subst,COMP_REPLACERS.values())
>         rep=all_seccions(groups)
>         rep_out=''.join(x[0]+x[1] for x in rep)
>         calc=calc_seccions(rep)
>         calc_out=''.join(x[0]+x[1] for x in calc)
>         deltas=calc_deltas(calc)
>         result=eval(calc_out,{},{})
snip

You are using 'eval' which isn't safe if its inputs are dangerous.  If
you are controlling the inputs, you might be interested in the
optional arguments to 'eval'.

>>> a= '-1000.00 < A < 0.00'
>>> eval( a, { 'A': -100 } )
True
>>> eval( a, { 'A': -1000 } )
False

The syntax is slightly different for Python 2.  For the replacement of
'LE', I assume you require spaces on both sides.

>>> a= '-1000.00 LE A LE 0.00'
>>> b= a.replace( ' LE ', ' <= ' )
>>> b
'-1000.00 <= A <= 0.00'
>>> eval( b, { 'A': -1000 } )
True
>>> eval( b, { 'A': -1001 } )
False

If you need something more flexible, the 'ast' module gives you more
options.  The string has to be a valid Python module to start with.

FYI, have you checked order of precedence in your custom rule set to
match Python's?



More information about the Python-list mailing list