1
# -*- coding: UTF-8 -*-
2
# eqnparser.py, generic equation parser by Reinier Heeres <reinier@heeres.eu>
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
# 2007-07-03: rwh, first version
22
_logger = logging.getLogger('EqnParser')
25
from mathlib import MathLib
26
from plotlib import PlotLib
27
from eqnparserhelp import EqnParserHelp
29
from rational import Rational
31
from gettext import gettext as _
33
_generic_error = _('Parse error')
36
def __init__(self, eqn):
43
def __init__(self, str):
45
self.strlen = len(str)
52
self.result_type = EqnParser.TYPE_UNKNOWN
53
self.error_code = self.OK
55
self.error_range = (0, 0)
57
def state_string(self):
58
return _('level: %d, ofs %d') % (self.level, self.ofs)
61
return self.error_code == self.OK and self.ofs < self.strlen
65
if self.ofs < self.strlen:
66
self.char = self.str[self.ofs]
73
if self.ofs < self.strlen and self.ofs >= 0:
74
self.char = self.str[self.ofs]
81
self.char = self.str[o]
89
def set_type(self, t):
90
if self.result_type == EqnParser.TYPE_UNKNOWN or t is EqnParser.TYPE_SYMBOLIC:
93
elif self.result_type != t:
94
_logger.debug('Type error')
99
def set_error(self, c, msg=None, range=None):
103
if range is not None:
104
_logger.debug('Setting range: %r', range)
105
self.error_range = range
107
_logger.debug('Setting offset: %d', self.ofs)
108
self.error_range = (self.ofs, self.ofs + 1)
111
return self.error_code
113
def set_error_range(self, r):
116
def format_error(self):
117
msg = _("Error at %d") % (self.error_range[0])
118
if self.error_msg is not None and len(self.error_msg) > 0:
119
msg += ": %s" % (self.error_msg)
122
def copy_error(self, ps):
123
"""Copy error state from recursively created ParserState object"""
124
self.error_code = ps.error_code
125
self.error_msg = ps.error_msg
126
self.error_range = (ps.error_range[0] + ps.ofs, ps.error_range[1] + ps.ofs)
135
INVALID_OP = ('err', OP_INVALID, 0, lambda x: False)
137
NAME_CHARS = u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789 '
138
DIGITS = u'0123456789'
139
SPACE_CHARS = u'\t \r\n'
141
# These will be filled from register_operator
151
def __init__(self, ml=None):
159
self.pl = PlotLib(self)
162
self.parse_var = {} # Whether or not to parse this variable recursively
166
self.cached_diadic_ops = None
167
self.cached_pre_ops = None
168
self.cached_post_ops = None
170
self.register_function('exp', lambda x: self.ml.exp(x[0]), {"nargs": 1})
171
self.register_function('ln', lambda x: self.ml.ln(x[0]), {"nargs": 1})
172
self.register_function('log', lambda x: self.ml.log10(x[0]), {"nargs": 1})
173
self.register_function('log10', lambda x: self.ml.log10(x[0]), {"nargs": 1})
174
self.register_function('pow', lambda x: self.ml.pow(x[0], x[1]), {"nargs": 2})
176
self.register_function('sqrt', lambda x: self.ml.sqrt(x[0]), {"nargs": 1})
178
self.register_function('sin', lambda x: self.ml.sin(x[0]), {"nargs": 1})
179
self.register_function('cos', lambda x: self.ml.cos(x[0]), {"nargs": 1})
180
self.register_function('tan', lambda x: self.ml.tan(x[0]), {"nargs": 1})
182
self.register_function('asin', lambda x: self.ml.asin(x[0]), {"nargs": 1})
183
self.register_function('acos', lambda x: self.ml.acos(x[0]), {"nargs": 1})
184
self.register_function('atan', lambda x: self.ml.atan(x[0]), {"nargs": 1})
186
self.register_function('sinh', lambda x: self.ml.sinh(x[0]), {"nargs": 1})
187
self.register_function('cosh', lambda x: self.ml.cosh(x[0]), {"nargs": 1})
188
self.register_function('tanh', lambda x: self.ml.tanh(x[0]), {"nargs": 1})
190
self.register_function('asinh', lambda x: self.ml.asinh(x[0]), {"nargs": 1})
191
self.register_function('acosh', lambda x: self.ml.acosh(x[0]), {"nargs": 1})
192
self.register_function('atanh', lambda x: self.ml.atanh(x[0]), {"nargs": 1})
194
self.register_function('round', lambda x: self.ml.round(x[0]), {"nargs": 1})
195
self.register_function('floor', lambda x: self.ml.floor(x[0]), {"nargs": 1})
196
self.register_function('ceil', lambda x: self.ml.ceil(x[0]), {"nargs": 1})
198
self.register_function('rand', lambda x: self.ml.rand_float(), {"nargs": 0})
199
self.register_function('randint', lambda x: self.ml.rand_int(), {"nargs": 0})
201
self.register_function('mod', lambda x: self.ml.mod(x[0], x[1]), {"nargs": 2})
203
self.register_function('factorize', lambda x: self.ml.factorize(x[0]), {"nargs": 1})
205
self.register_function('plot', lambda x: self.pl.plot(x[0], x[1]), {"nargs": 2, 'parse_options': False})
207
self.register_function('help', lambda x: EqnParserHelp.help(x[0]), {"nargs": 1, 'parse_options': False})
209
self.register_function('functions', lambda x: self.functions_string(), {"nargs": 0})
210
self.register_function('variables', lambda x: self.variables_string(), {"nargs": 0})
211
self.register_function('operators', lambda x: self.operators_string(), {"nargs": 0})
213
self.register_operator('+', self.OP_DIADIC, 0, lambda x: self.ml.add(x[0], x[1]))
214
self.register_operator('+', self.OP_PRE, 2, lambda x: x[0])
215
self.register_operator('-', self.OP_DIADIC, 0, lambda x: self.ml.sub(x[0], x[1]))
216
self.register_operator('-', self.OP_PRE, 2, lambda x: self.ml.negate(x[0]))
217
self.register_operator('*', self.OP_DIADIC, 1, lambda x: self.ml.mul(x[0], x[1]))
218
self.register_operator(u'⨯', self.OP_DIADIC, 1, lambda x: self.ml.mul(x[0], x[1]))
219
self.register_operator(u'×', self.OP_DIADIC, 1, lambda x: self.ml.mul(x[0], x[1]))
220
self.register_operator('/', self.OP_DIADIC, 1, lambda x: self.div_operator(x[0], x[1]))
221
self.register_operator(u'÷', self.OP_DIADIC, 1, lambda x: self.div_operator(x[0], x[1]))
223
self.register_operator('^', self.OP_DIADIC, 2, lambda x: self.ml.pow(x[0], x[1]))
224
self.register_operator('**', self.OP_DIADIC, 2, lambda x: self.ml.pow(x[0], x[1]))
226
self.register_operator('!', self.OP_POST, 0, lambda x: self.ml.factorial(x[0]))
228
self.register_operator('&', self.OP_DIADIC, 0, lambda x: x[0] and x[1])
229
self.register_function('and', lambda x: x[0] and x[1], {"nargs": 2})
230
self.register_operator('|', self.OP_DIADIC, 0, lambda x: x[0] or x[1])
231
self.register_function('or', lambda x: x[0] or x[1], {"nargs": 2})
232
self.register_operator('!', self.OP_PRE, 0, lambda x: not x[0])
233
self.register_function('not', lambda x: not x[0], {"nargs": 1})
235
# self.register_operator('^', self.OP_PRE, 0, lambda x: not x[0])
236
self.register_function('xor', lambda x: (x[0] and not x[1]) or (x[1] and not x[0]), {"nargs": 2})
238
self.register_operator('=', self.OP_DIADIC, 0, lambda x: x[0] == x[1])
239
self.register_operator('!=', self.OP_DIADIC, 0, lambda x: x[0] != x[1])
240
self.register_operator('<', self.OP_DIADIC, 0, lambda x: x[0] < x[1])
241
self.register_operator('>', self.OP_DIADIC, 0, lambda x: x[0] > x[1])
243
self.register_operator('<<', self.OP_DIADIC, 0, lambda x: self.ml.shift_left(x[0], x[1]))
244
self.register_operator('>>', self.OP_DIADIC, 0, lambda x: self.ml.shift_right(x[0], x[1]))
246
self.register_operator('%', self.OP_DIADIC, 2, lambda x: self.ml.mod(x[0], x[1]))
249
_("Use help(test) for help about 'test', or help(index) for the index"),
252
def register_function(self, name, f, opts):
253
self.functions[name] = (f, opts)
254
self.functions[_(name)] = (f, opts)
256
def register_operator(self, op, type, presedence, f):
257
self.operators.append((op, type, presedence, f))
259
if op[0] not in self.OP_START_CHARS:
260
self.OP_START_CHARS += op[0]
262
if c not in self.OP_CHARS:
265
def get_diadic_operators(self):
266
if self.cached_diadic_ops == None:
267
self.cached_diadic_ops = []
268
for (op, type, presedence, f) in self.operators:
269
if type == self.OP_DIADIC:
270
self.cached_diadic_ops.append(op)
271
return self.cached_diadic_ops
273
def get_pre_operators(self):
274
if self.cached_pre_ops == None:
275
self.cached_pre_ops = []
276
for (op, type, presedence, f) in self.operators:
277
if type == self.OP_PRE:
278
self.cached_pre_ops.append(op)
279
return self.cached_pre_ops
281
def get_post_operators(self):
282
if self.cached_post_ops == None:
283
self.cached_post_ops = []
284
for (op, type, presedence, f) in self.operators:
285
if type == self.OP_POST:
286
self.cached_post_ops.append(op)
287
return self.cached_post_ops
289
def reset_variable_level(self, level):
291
# for i in self.variables.keys():
292
# self.variables[i].highest_level = level
294
def set_var(self, name, val, parse=True):
295
if type(val) is types.FloatType:
296
self.variables[name] = self.ml.d(val)
298
self.variables[name] = val
299
self.parse_var[name] = parse
301
def get_var(self, name):
302
if name in self.variables:
303
return self.variables[name]
307
def lookup_var(self, name, ps):
308
c = self.ml.get_constant(name)
312
if name in self.variables.keys():
313
# if self.variables[name].highest_level > 0 and self.variables[name].highest_level != ps.level:
314
# _logger.error('EqnParser.lookup_var(): recursion detected')
316
# self.variables[name].highest_level = level
317
if (type(self.variables[name]) is types.UnicodeType or type(self.variables[name]) is types.StringType) \
318
and self.parse_var[name]:
319
return self.parse(self.variables[name], reset=False)
321
return self.variables[name]
323
_logger.debug('variable %s not defined', name)
324
ps.set_type(self.TYPE_SYMBOLIC)
329
for name in self.variables:
330
list.append((name, self.variables[name]))
333
def get_var_names(self, start=None):
334
names = self.variables.keys()
342
if name[:len(start)] == start:
343
retnames.append(name)
346
def get_function_names(self):
347
names = self.functions.keys()
351
def eval_func(self, func, args, level):
352
if func not in self.functions:
353
_logger.error(_("Function '%s' not defined"), func)
354
self.ps.set_error(ParserState.PARSE_ERROR, msg=_("Function '%s' not defined") % (func))
357
(f, opts) = self.functions[func]
358
if len(args) != opts['nargs']:
359
_logger.error(_('Invalid number of arguments (%d instead of %d)'), len(args), opts['nargs'])
360
self.ps.set_error(ParserState.PARSE_ERROR, msg=_('function takes %d args') % (opts['nargs']))
363
if 'parse_options' in opts and opts['parse_options'] == False:
367
for i in range(len(args)):
368
pargs.append(self.parse(args[i], reset=False))
370
_logger.error(_('Unable to parse argument %d: \'%s\''), i, args[i])
371
self.ps.set_error(ParserState.PARSE_ERROR, msg=_('Unable to parse argument %d: \'%s\'') % (i, args[i]))
377
# Maybe we should map exceptions to more obvious error messages
378
except Exception, inst:
380
self.ps.set_error(ParserState.PARSE_ERROR, msg=_("Function error: %s") % (str(inst)))
382
_logger.debug('Function \'%s\' returned %s', func, self.ml.format_number(res))
385
def parse_number(self, ps):
389
while ps.more() and ps.char in self.DIGITS:
393
if ps.char == '.' or ps.char == self.ml.fraction_sep:
395
while ps.more() and ps.char in self.DIGITS:
399
if ps.char is not None and ps.char in u'eE':
401
if ps.char is not None and ps.char in u'+-':
403
while ps.more() and ps.char in self.DIGITS:
406
_logger.debug('parse_number(): %d - %d: %s', startofs, ps.ofs, ps.str[startofs:ps.ofs])
407
n = self.ml.parse_number(ps.str[startofs:ps.ofs])
410
def valid_operator(self, opstr, left_val):
411
for op_tuple in self.operators:
412
(op, type, presedence, f) = op_tuple
414
if type == self.OP_DIADIC and left_val is not None:
416
elif type == self.OP_POST and left_val is not None:
418
elif type == self.OP_PRE and left_val is None:
422
def parse_operator(self, ps, left_val):
425
while ps.more() and ps.char in self.OP_CHARS:
427
op2 = self.valid_operator(ps.str[startofs:ps.ofs], left_val)
435
_logger.debug('parse_operator(): %d - %d: %s', startofs, ps.ofs, ps.str[startofs:ps.ofs])
438
return self.INVALID_OP
440
def parse_func_args(self, ps):
444
while ps.more() and pcount > 0:
445
if ps.char == ',' and pcount == 1:
446
args.append(ps.str[startofs:ps.ofs])
447
startofs = ps.ofs + 1
452
if pcount == 0 and (ps.ofs - startofs) > 0:
453
args.append(ps.str[startofs:ps.ofs])
455
_logger.debug('parse_func_args(): %d - %d: %r', startofs, ps.ofs, args)
458
def parse_var_func(self, ps):
460
while ps.more() and ps.char in self.NAME_CHARS:
462
name = ps.str[startofs:ps.ofs]
463
name.strip(self.SPACE_CHARS)
464
name.rstrip(self.SPACE_CHARS)
469
_logger.debug('parse_var_func(): function %d - %d: %s', startofs, ps.ofs, name)
470
args = self.parse_func_args(ps)
471
ret = self.eval_func(name, args, ps.level)
473
ps.set_error_range((startofs, ps.ofs))
478
_logger.debug('parse_var_func(): variable %d - %d: %s', startofs, ps.ofs, name)
479
res = self.lookup_var(name, ps)
481
ps.set_error(ParserState.PARSE_ERROR, msg=_("Variable '%s' not defined") % (name), range=(startofs, ps.ofs))
484
def _parse(self, ps, presedence=None):
485
if presedence is None:
487
_logger.debug('_parse(): %s, presedence: %r', ps.state_string(), presedence)
494
# _logger.debug('Looking at %r, ofs %d in %r', ps.char, ps.ofs, ps.str)
497
if ps.char in self.SPACE_CHARS:
500
# Left parenthesis: parse sub-expression
502
if not (left_val is None or left_val is not None and op is not None):
503
_logger.error('Parse error (left parenthesis)')
504
ps.set_error(ParserState.PARSE_ERROR, msg=_("Left parenthesis unexpected"))
508
left_val = self._parse(ps)
510
# Right parenthesis: return from parsing sub-expression
511
# -If we are looking ahead because of operator presedence return value
512
# -Else move to next character, decrease level and return value
514
if presedence is not None:
516
_logger.error(_('Parse error (right parenthesis)'))
517
ps.set_error(ParserState.PARSE_ERROR, msg=_("Right parenthesis unexpected"))
520
_logger.debug('returning %s', self.ml.format_number(left_val))
527
_logger.error(_('Parse error (right parenthesis, no left_val)'))
528
ps.set_error(ParserState.PARSE_ERROR, msg=_("Right parenthesis unexpected"))
531
_logger.debug('returning %s', self.ml.format_number(left_val))
534
_logger.error(_('Parse error (right parenthesis, no level to close)'))
535
ps.set_error(ParserState.PARSE_ERROR, msg=_("Right parenthesis unexpected"))
539
elif ps.char == '.' or ps.char in self.DIGITS:
540
if right_val is not None or left_val is not None:
541
_logger.error(_('Number not expected'))
542
ps.set_error(ParserState.PARSE_ERROR, msg=_("Number not expected"))
545
left_val = self.parse_number(ps)
548
elif ps.char in self.OP_START_CHARS:
550
ps.set_error(ParserState.PARSE_ERROR, msg=_("Operator not expected"))
554
op = self.parse_operator(ps, left_val)
555
(opstr, otype, opres, of) = op
558
if otype == self.OP_DIADIC:
559
if presedence is not None and opres <= presedence:
561
_logger.debug('returning %s (by presedence, %d)', self.ml.format_number(left_val), ps.ofs)
564
right_val = self._parse(ps, presedence=opres)
565
if right_val is None and self.ps.get_error() == ParserState.OK:
566
_logger.error(_('Parse error: number or variable expected'))
567
ps.set_error(ParserState.PARSE_ERROR, msg=_("Number or variable expected"))
569
elif right_val is None:
572
res = of([left_val, right_val])
573
_logger.debug('OP: %s (%r), %s (%r) ==> %s (%r)', self.ml.format_number(left_val), left_val, self.ml.format_number(right_val), right_val, self.ml.format_number(res), res)
578
# Operator that goes after value
579
elif otype == self.OP_POST:
581
_logger.debug('OP POST: %s ==> %s', self.ml.format_number(left_val), self.ml.format_number(res))
585
# Operator that goes before value
586
elif otype == self.OP_PRE:
587
right_val = self._parse(ps, presedence=opres)
588
if right_val is None:
590
left_val = of([right_val])
591
_logger.debug('OP PRE: %s ==> %s', self.ml.format_number(right_val), self.ml.format_number(left_val))
594
elif otype == self.OP_INVALID:
595
_logger.debug('Invalid operator')
596
ps.set_error(ParserState.PARSE_ERROR, msg=_("Invalid operator"), range=(startofs, ps.ofs))
599
# Parse variable or function
601
if left_val is not None:
602
_logger.debug('Operator expected: %r', self.OP_START_CHARS)
603
ps.set_error(ParserState.PARSE_ERROR, msg=_("Operator expected"))
606
left_val = self.parse_var_func(ps)
608
if not ps.more() and ps.level > 0:
609
_logger.debug('Parse error: \')\' expected')
610
ps.set_error(ParserState.PARSE_ERROR, msg=_("Right parenthesis unexpected"))
612
elif op is None and left_val is not None:
613
_logger.debug('returning %s', self.ml.format_number(left_val))
616
_logger.error(_('_parse(): returning None'))
617
# Should be set somewhere already
618
# ps.set_error(ParserState.PARSE_ERROR)
621
def get_error_offset(self):
622
return self.ps.error_range[0]
624
def get_error_range(self):
625
return self.ps.error_range
627
def parse(self, eqn, reset=True):
628
"""Construct ParserState object and call _parse"""
630
# Parse everything in unicode
631
if type(eqn) is types.StringType:
634
_logger.debug('parse(): %r', eqn)
635
self.reset_variable_level(0)
641
self.ps = ParserState(eqn)
642
ret = self._parse(self.ps)
643
if oldps is not None:
644
oldps.copy_error(self.ps)
649
def functions_string(self):
651
for key in self.functions.keys():
655
def variables_string(self):
657
for key in self.variables.keys():
661
def operators_string(self):
663
for (op, type, p, f) in self.operators:
667
def div_operator(self, a, b):
668
if b == 0 or b == 0.0:
669
return _('Undefined')
670
if isinstance(a, Rational) or isinstance(b, Rational):
672
elif self.ml.is_int(a) and float(self.ml.abs(a)) < 1e12 and \
673
self.ml.is_int(b) and float(self.ml.abs(b)) < 1e12:
674
return Rational(a, b)
676
return self.ml.div(a, b)