Package madgraph :: Package iolibs :: Module ufo_expression_parsers
[hide private]
[frames] | no frames]

Source Code for Module madgraph.iolibs.ufo_expression_parsers

  1  ################################################################################ 
  2  # 
  3  # Copyright (c) 2009 The MadGraph5_aMC@NLO Development team and Contributors 
  4  # 
  5  # This file is a part of the MadGraph5_aMC@NLO project, an application which  
  6  # automatically generates Feynman diagrams and matrix elements for arbitrary 
  7  # high-energy processes in the Standard Model and beyond. 
  8  # 
  9  # It is subject to the MadGraph5_aMC@NLO license which should accompany this  
 10  # distribution. 
 11  # 
 12  # For more information, visit madgraph.phys.ucl.ac.be and amcatnlo.web.cern.ch 
 13  # 
 14  ################################################################################ 
 15   
 16  """Parsers for algebraic expressions coming from UFO, outputting into 
 17  different languages/frameworks (Fortran and Pythia8). Uses the PLY 3.3 
 18  Lex + Yacc framework""" 
 19   
 20  import logging 
 21  import os 
 22  import re 
 23  import sys 
 24  import copy 
 25   
 26  root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] 
 27  sys.path.append(os.path.join(root_path, os.path.pardir)) 
 28   
 29  import madgraph.various.misc as misc 
 30   
 31  from madgraph import MadGraph5Error 
 32  import vendor.ply.lex as lex 
 33  import vendor.ply.yacc as yacc 
 34  import models.check_param_card as check_param_card 
 35   
 36  logger = logging.getLogger('madgraph.ufo_parsers') 
 37   
 38  # PLY lexer class 
 39   
40 -class ModelError(MadGraph5Error):
41 """Appropriate Error for a wrong parsing"""
42
43 -class UFOExpressionParser(object):
44 """A base class for parsers for algebraic expressions coming from UFO.""" 45 46 parsed_string = "" 47 logical_equiv = {} 48
49 - def __init__(self, **kw):
50 """Initialize the lex and yacc""" 51 52 modname = self.__class__.__name__ 53 self.debugfile = os.path.devnull 54 self.tabmodule = os.path.join(root_path, "iolibs", modname + "_" + "parsetab.py") 55 lex.lex(module=self, debug=0) 56 self.y=yacc.yacc(module=self, debug=0, debugfile=self.debugfile, 57 tabmodule=self.tabmodule)
58
59 - def parse(self, buf):
60 """Parse the string buf""" 61 self.y.parse(buf) 62 return self.parsed_string
63 64 # List of tokens and literals 65 tokens = ( 66 'LOGICAL','LOGICALCOMB','POWER', 'CSC', 'SEC', 'ACSC', 'ASEC', 'TAN', 67 'SQRT', 'CONJ', 'RE', 'RE2', 'IM', 'PI', 'COMPLEX', 'FUNCTION', 'IF','ELSE', 68 'VARIABLE', 'NUMBER','COND','REGLOG', 'REGLOGP', 'REGLOGM','RECMS','ARG' 69 ) 70 literals = "=+-*/()," 71 72 # Definition of tokens 73
74 - def t_CSC(self, t):
75 r'(?<!\w)csc(?=\()' 76 return t
77 - def t_SEC(self, t):
78 r'(?<!\w)sec(?=\()' 79 return t
80 - def t_ACSC(self, t):
81 r'(?<!\w)acsc(?=\()' 82 return t
83 - def t_TAN(self, t):
84 r'(?<!\w)tan(?=\()|(?<!\w)cmath.tan(?=\()' 85 return t
86 - def t_ASEC(self, t):
87 r'(?<!\w)asec(?=\()' 88 return t
89 - def t_REGLOG(self, t):
90 r'(?<!\w)reglog(?=\()' 91 return t
92 - def t_REGLOGP(self, t):
93 r'(?<!\w)reglogp(?=\()' 94 return t
95 - def t_REGLOGM(self, t):
96 r'(?<!\w)reglogm(?=\()' 97 return t
98 - def t_RECMS(self, t):
99 r'(?<!\w)recms(?=\()' 100 return t
101 - def t_COND(self, t):
102 r'(?<!\w)cond(?=\()' 103 return t
104 - def t_ARG(self,t):
105 r'(?<!\w)arg(?=\()' 106 return t
107 - def t_IF(self, t):
108 r'(?<!\w)if\s' 109 return t
110 - def t_ELSE(self, t):
111 r'(?<!\w)else\s' 112 return t
113 - def t_LOGICAL(self, t):
114 r'==|!=|<=|>=|<|>' 115 return t
116 - def t_LOGICALCOMB(self, t):
117 r'(?<!\w)and(?=[\s\(])|(?<!\w)or(?=[\s\(])' 118 return t
119 - def t_SQRT(self, t):
120 r'cmath\.sqrt' 121 return t
122 - def t_PI(self, t):
123 r'cmath\.pi' 124 return t
125 - def t_CONJ(self, t):
126 r'complexconjugate' 127 return t
128 - def t_IM(self, t):
129 r'(?<!\w)im(?=\()' 130 return t
131 - def t_RE(self, t):
132 r'(?<!\w)re(?=\()' 133 return t
134 - def t_RE2(self, t):
135 r'\.real|\.imag' 136 return t
137
138 - def t_COMPLEX(self, t):
139 r'(?<!\w)complex(?=\()' 140 return t
141 - def t_FUNCTION(self, t):
142 r'(cmath\.){0,1}[a-zA-Z_][0-9a-zA-Z_]*(?=\()' 143 return t
144 - def t_VARIABLE(self, t):
145 r'[a-zA-Z_][0-9a-zA-Z_]*' 146 return t
147 148 t_NUMBER = r'([0-9]+\.[0-9]*|\.[0-9]+|[0-9]+)([eE][+-]{0,1}[0-9]+){0,1}j{0,1}' 149 t_POWER = r'\*\*' 150 151 t_ignore = " \t" 152 153 re_cmath_function = re.compile("cmath\.(?P<name>[0-9a-zA-Z_]+)") 154
155 - def t_newline(self, t):
156 r'\n+' 157 t.lexer.lineno += t.value.count("\n")
158
159 - def t_error(self, t):
160 logger.error("Illegal character '%s'" % t.value[0]) 161 t.lexer.skip(1)
162 163 # Build the lexer
164 - def build(self,**kwargs):
165 self.lexer = lex.lex(module=self, **kwargs)
166 167 # Definitions for the PLY yacc parser 168 # Parsing rules 169 precedence = ( 170 ('right', 'LOGICALCOMB'), 171 ('right', 'LOGICAL'), 172 ('right','IF'), 173 ('right','ELSE'), 174 ('left','='), 175 ('left','+','-'), 176 ('left','*','/'), 177 ('left', 'RE2'), 178 ('right','UMINUS'), 179 ('left','POWER'), 180 ('right','REGLOG'), 181 ('right','REGLOGP'), 182 ('right','REGLOGM'), 183 ('right','RECMS'), 184 ('right','ARG'), 185 ('right','CSC'), 186 ('right','SEC'), 187 ('right','ACSC'), 188 ('right','ASEC'), 189 ('right','SQRT'), 190 ('right','CONJ'), 191 ('right','RE'), 192 ('right','IM'), 193 ('right','FUNCTION'), 194 ('right','COMPLEX'), 195 ('right','COND'), 196 ) 197 198 # Dictionary of parser expressions
199 - def p_statement_expr(self, p):
200 'statement : expression' 201 self.parsed_string = p[1]
202
203 - def p_expression_binop(self, p):
204 '''expression : expression '=' expression 205 | expression '+' expression 206 | expression '-' expression 207 | expression '*' expression 208 | expression '/' expression''' 209 p[0] = p[1] + p[2] + p[3]
210
211 - def p_expression_logical(self, p):
212 '''boolexpression : expression LOGICAL expression''' 213 if p[2] not in self.logical_equiv: 214 p[0] = p[1] + p[2] + p[3] 215 else: 216 p[0] = p[1] + self.logical_equiv[p[2]] + p[3]
217
218 - def p_expression_logicalcomb(self, p):
219 '''boolexpression : boolexpression LOGICALCOMB boolexpression''' 220 if p[2] not in self.logical_equiv: 221 p[0] = p[1] + p[2] + p[3] 222 else: 223 p[0] = p[1] + self.logical_equiv[p[2]] + p[3]
224
225 - def p_expression_uminus(self, p):
226 "expression : '-' expression %prec UMINUS" 227 p[0] = '-' + p[2]
228
229 - def p_group_parentheses(self, p):
230 "group : '(' expression ')'" 231 p[0] = '(' + p[2] +')'
232
233 - def p_group_parentheses_boolexpr(self, p):
234 "boolexpression : '(' boolexpression ')'" 235 p[0] = '(' + p[2] +')'
236
237 - def p_expression_group(self, p):
238 "expression : group" 239 p[0] = p[1]
240
241 - def p_expression_function1(self, p):
242 "expression : FUNCTION '(' expression ')'" 243 p1 = p[1] 244 re_groups = self.re_cmath_function.match(p1) 245 if re_groups: 246 p1 = re_groups.group("name") 247 p[0] = p1 + '(' + p[3] + ')'
248
249 - def p_expression_function2(self, p):
250 "expression : FUNCTION '(' expression ',' expression ')'" 251 p1 = p[1] 252 re_groups = self.re_cmath_function.match(p1) 253 if re_groups: 254 p1 = re_groups.group("name") 255 p[0] = p1 + '(' + p[3] + ',' + p[5] + ')'
256
257 - def p_error(self, p):
258 if p: 259 raise ModelError("Syntax error at '%s' (%s)." %(p.value,p)) 260 else: 261 logger.error("Syntax error at EOF") 262 self.parsed_string = "Error"
263
264 -class UFOExpressionParserFortran(UFOExpressionParser):
265 """A parser for UFO algebraic expressions, outputting 266 Fortran-style code.""" 267 268 # The following parser expressions need to be defined for each 269 # output language/framework 270 271 logical_equiv = {'==':'.EQ.', 272 '>=':'.GE.', 273 '<=':'.LE.', 274 '!=':'.NE.', 275 '>':'.GT.', 276 '<':'.LT.', 277 'or':'.OR.', 278 'and':'.AND.'} 279
280 - def p_expression_number(self, p):
281 "expression : NUMBER" 282 if p[1].endswith('j'): 283 p[0] = ('DCMPLX(0d0, %e)' % float(p[1][:-1])).replace('e', 'd') 284 else: 285 p[0] = ('%e' % float(p[1])).replace('e', 'd')
286
287 - def p_expression_variable(self, p):
288 "expression : VARIABLE" 289 p[0] = p[1].lower()
290
291 - def p_expression_power(self, p):
292 'expression : expression POWER expression' 293 try: 294 p3 = float(p[3].replace('d','e')) 295 # Chebck if exponent is an integer 296 if p3 == int(p3): 297 p3 = str(int(p3)) 298 p[0] = p[1] + "**" + p3 299 else: 300 p[0] = p[1] + "**" + p[3] 301 except Exception: 302 p[0] = p[1] + "**" + p[3]
303
304 - def p_expression_if(self,p):
305 "expression : expression IF boolexpression ELSE expression " 306 p[0] = 'CONDIF(%s,DCMPLX(%s),DCMPLX(%s))' % (p[3], p[1], p[5])
307
308 - def p_expression_ifimplicit(self,p):
309 "expression : expression IF expression ELSE expression " 310 p[0] = 'CONDIF(DCMPLX(%s).NE.(0d0,0d0),DCMPLX(%s),DCMPLX(%s))'\ 311 %(p[3], p[1], p[5])
312
313 - def p_expression_cond(self, p):
314 "expression : COND '(' expression ',' expression ',' expression ')'" 315 p[0] = 'COND(DCMPLX('+p[3]+'),DCMPLX('+p[5]+'),DCMPLX('+p[7]+'))'
316
317 - def p_expression_recms(self, p):
318 "expression : RECMS '(' boolexpression ',' expression ')'" 319 p[0] = 'RECMS('+p[3]+',DCMPLX('+p[5]+'))'
320
321 - def p_expression_complex(self, p):
322 "expression : COMPLEX '(' expression ',' expression ')'" 323 p[0] = 'DCMPLX(' + p[3] + ',' + p[5] + ')'
324
325 - def p_expression_func(self, p):
326 '''expression : CSC group 327 | SEC group 328 | ACSC group 329 | ASEC group 330 | RE group 331 | IM group 332 | ARG group 333 | SQRT group 334 | CONJ group 335 | REGLOG group 336 | REGLOGP group 337 | REGLOGM group 338 | TAN group''' 339 340 if p[1] == 'csc': p[0] = '1d0/sin' + p[2] 341 elif p[1] == 'sec': p[0] = '1d0/cos' + p[2] 342 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')' 343 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')' 344 elif p[1] in ['tan', 'cmath.tan'] : p[0] = 'tan(dble' + p[2]+')' 345 elif p[1] == 're': p[0] = 'dble' + p[2] 346 elif p[1] == 'im': p[0] = 'dimag' + p[2] 347 elif p[1] == 'arg': p[0] = 'arg(DCMPLX'+p[2]+')' 348 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt(dcmplx' + p[2]+')' 349 elif p[1] == 'complexconjugate': p[0] = 'conjg(DCMPLX' + p[2]+')' 350 elif p[1] == 'reglog': p[0] = 'reglog(DCMPLX' + p[2] +')' 351 elif p[1] == 'reglogp': p[0] = 'reglogp(DCMPLX' + p[2] + ')' 352 elif p[1] == 'reglogm': p[0] = 'reglogm(DCMPLX' + p[2] + ')'
353 354
355 - def p_expression_real(self, p):
356 ''' expression : expression RE2 ''' 357 358 if p[2] == '.real': 359 if p[1].startswith('('): 360 p[0] = 'dble' +p[1] 361 else: 362 p[0] = 'dble(%s)' % p[1] 363 elif p[2] == '.imag': 364 if p[1].startswith('('): 365 p[0] = 'dimag' +p[1] 366 else: 367 p[0] = 'dimag(%s)' % p[1]
368
369 - def p_expression_pi(self, p):
370 '''expression : PI''' 371 p[0] = 'pi'
372
373 -class UFOExpressionParserMPFortran(UFOExpressionParserFortran):
374 """A parser for UFO algebraic expressions, outputting 375 Fortran-style code for quadruple precision computation.""" 376 377 mp_prefix = check_param_card.ParamCard.mp_prefix 378 379 # The following parser expressions need to be defined for each 380 # output language/framework 381
382 - def p_expression_number(self, p):
383 "expression : NUMBER" 384 385 if p[1].endswith('j'): 386 p[0] = 'CMPLX(0.000000e+00_16, %e_16 ,KIND=16)' % float(p[1][:-1]) 387 else: 388 p[0] = '%e_16' % float(p[1])
389
390 - def p_expression_variable(self, p):
391 "expression : VARIABLE" 392 # All the multiple_precision variables are defined with the prefix _MP_" 393 p[0] = (self.mp_prefix+p[1]).lower()
394
395 - def p_expression_power(self, p):
396 'expression : expression POWER expression' 397 try: 398 p3 = float(p[3].replace('_16','')) 399 # Check if exponent is an integer 400 if p3 == int(p3): 401 p3 = str(int(p3)) 402 p[0] = p[1] + "**" + p3 403 else: 404 p[0] = p[1] + "**" + p[3] 405 except Exception: 406 p[0] = p[1] + "**" + p[3]
407
408 - def p_expression_if(self,p):
409 "expression : expression IF boolexpression ELSE expression " 410 p[0] = 'MP_CONDIF(%s,CMPLX(%s,KIND=16),CMPLX(%s,KIND=16))' % (p[3], p[1], p[5])
411
412 - def p_expression_ifimplicit(self,p):
413 "expression : expression IF expression ELSE expression " 414 p[0] = 'MP_CONDIF(CMPLX(%s,KIND=16).NE.(0.0e0_16,0.0e0_16),CMPLX(%s,KIND=16),CMPLX(%s,KIND=16))'\ 415 %(p[3], p[1], p[5])
416
417 - def p_expression_complex(self, p):
418 "expression : COMPLEX '(' expression ',' expression ')'" 419 p[0] = 'CMPLX(' + p[3] + ',' + p[5] + ',KIND=16)'
420
421 - def p_expression_cond(self, p):
422 "expression : COND '(' expression ',' expression ',' expression ')'" 423 p[0] = 'MP_COND(CMPLX('+p[3]+',KIND=16),CMPLX('+p[5]+\ 424 ',KIND=16),CMPLX('+p[7]+',KIND=16))'
425
426 - def p_expression_recms(self, p):
427 "expression : RECMS '(' boolexpression ',' expression ')'" 428 p[0] = 'MP_RECMS('+p[3]+',CMPLX('+p[5]+',KIND=16))'
429
430 - def p_expression_func(self, p):
431 '''expression : CSC group 432 | SEC group 433 | ACSC group 434 | ASEC group 435 | RE group 436 | IM group 437 | ARG group 438 | SQRT group 439 | CONJ group 440 | REGLOG group 441 | REGLOGP group 442 | REGLOGM group 443 | TAN group''' 444 445 if p[1] == 'csc': p[0] = '1e0_16/cos' + p[2] 446 elif p[1] == 'sec': p[0] = '1e0_16/sin' + p[2] 447 elif p[1] == 'acsc': p[0] = 'asin(1e0_16/' + p[2] + ')' 448 elif p[1] == 'asec': p[0] = 'acos(1e0_16/' + p[2] + ')' 449 elif p[1] in ['tan', 'cmath.tan']: p[0] = 'tan(real' + p[2]+')' 450 elif p[1] == 're': p[0] = 'real' + p[2] 451 elif p[1] == 'im': p[0] = 'imag' + p[2] 452 elif p[1] == 'arg': p[0] = 'mp_arg(CMPLX(' + p[2] + ',KIND=16))' 453 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt(CMPLX(' + p[2] + ',KIND=16))' 454 elif p[1] == 'complexconjugate': p[0] = 'conjg(CMPLX(' + p[2] + ',KIND=16))' 455 elif p[1] == 'reglog': p[0] = 'mp_reglog(CMPLX(' + p[2] +',KIND=16))' 456 elif p[1] == 'reglogp': p[0] = 'mp_reglogp(CMPLX(' + p[2] + ',KIND=16))' 457 elif p[1] == 'reglogm': p[0] = 'mp_reglogm(CMPLX(' + p[2] + ',KIND=16))'
458
459 - def p_expression_real(self, p):
460 ''' expression : expression RE2 ''' 461 462 if p[2] == '.real': 463 if p[1].startswith('('): 464 p[0] = 'real' +p[1] 465 else: 466 p[0] = 'real(%s)' % p[1] 467 elif p[2] == '.imag': 468 if p[1].startswith('('): 469 p[0] = 'imag' +p[1] 470 else: 471 p[0] = 'imag(%s)' % p[1]
472 473
474 - def p_expression_pi(self, p):
475 '''expression : PI''' 476 p[0] = self.mp_prefix+'pi'
477
478 -class UFOExpressionParserCPP(UFOExpressionParser):
479 """A parser for UFO algebraic expressions, outputting 480 C++-style code.""" 481 482 logical_equiv = {'==':'==', 483 '>=':'>=', 484 '<=':'<=', 485 '!=':'!=', 486 '>':'>', 487 '<':'<', 488 'or':'||', 489 'and':'&&'} 490 491 # The following parser expressions need to be defined for each 492 # output language/framework 493
494 - def p_expression_number(self, p):
495 'expression : NUMBER' 496 497 if p[1].endswith('j'): 498 p[0] = 'std::complex<double>(0., %e)' % float(p[1][:-1]) 499 else: 500 p[0] = ('%e' % float(p[1])).replace('e', 'd') 501 502 503 p[0] = p[1] 504 # Check number is an integer, if so add "." 505 if float(p[1]) == int(float(p[1])) and float(p[1]) < 1000: 506 p[0] = str(int(float(p[1]))) + '.'
507
508 - def p_expression_variable(self, p):
509 'expression : VARIABLE' 510 p[0] = p[1]
511
512 - def p_expression_if(self,p):
513 "expression : expression IF boolexpression ELSE expression " 514 p[0] = '(%s ? %s : %s)' % (p[3], p[1], p[5])
515
516 - def p_expression_ifimplicit(self,p):
517 "expression : expression IF expression ELSE expression " 518 p[0] = '(%s ? %s : %s)' % (p[3], p[1], p[5])
519
520 - def p_expression_cond(self, p):
521 "expression : COND '(' expression ',' expression ',' expression ')'" 522 p[0] = 'COND('+p[3]+','+p[5]+','+p[7]+')'
523
524 - def p_expression_recms(self, p):
525 "expression : RECMS '(' boolexpression ',' expression ')'" 526 p[0] = 'RECMS('+p[3]+','+p[5]+')'
527
528 - def p_expression_power(self, p):
529 'expression : expression POWER expression' 530 p1=p[1] 531 p3=p[3] 532 if p[1][0] == '(' and p[1][-1] == ')': 533 p1 = p[1][1:-1] 534 if p[3][0] == '(' and p[3][-1] == ')': 535 p3 = p[3][1:-1] 536 p[0] = 'pow(' + p1 + ',' + p3 + ')'
537
538 - def p_expression_complex(self, p):
539 "expression : COMPLEX '(' expression ',' expression ')'" 540 p[0] = 'std::complex<double>(' + p[3] + ',' + p[5] + ')'
541
542 - def p_expression_func(self, p):
543 '''expression : CSC group 544 | SEC group 545 | ACSC group 546 | ASEC group 547 | TAN group 548 | RE group 549 | IM group 550 | ARG group 551 | SQRT group 552 | CONJ group 553 | REGLOG group 554 | REGLOGP group 555 | REGLOGM group''' 556 if p[1] == 'csc': p[0] = '1./cos' + p[2] 557 elif p[1] == 'sec': p[0] = '1./sin' + p[2] 558 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')' 559 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')' 560 elif p[1] in ['tan', 'cmath.tan']: p[0] = 'tan' +p[2] 561 elif p[1] == 're': p[0] = 'real' + p[2] 562 elif p[1] == 'im': p[0] = 'imag' + p[2] 563 elif p[1] == 'arg':p[0] = 'arg' + p[2] 564 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt' + p[2] 565 elif p[1] == 'complexconjugate': p[0] = 'conj' + p[2] 566 elif p[1] == 'reglog': p[0] = 'reglog' + p[2] 567 elif p[1] == 'reglogp': p[0] = 'reglogp' + p[2] 568 elif p[1] == 'reglogm': p[0] = 'reglogm' + p[2]
569
570 - def p_expression_real(self, p):
571 ''' expression : expression RE2 ''' 572 573 if p[2] == '.real': 574 if p[1].startswith('('): 575 p[0] = 'real' +p[1] 576 else: 577 p[0] = 'real(%s)' % p[1] 578 elif p[2] == '.imag': 579 if p[1].startswith('('): 580 p[0] = 'imag' +p[1] 581 else: 582 p[0] = 'imag(%s)' % p[1]
583 584
585 - def p_expression_pi(self, p):
586 '''expression : PI''' 587 p[0] = 'M_PI'
588
589 -class UFOExpressionParserPythonIF(UFOExpressionParser):
590 """An ad hoc parser for UFO algebraic expressions with if statement, outputting 591 Python-style code, with the conditional 'if' expressions simplified using 592 pre-defined set of variables specified when instanciating this parser.""" 593 594 logical_equiv = {'==':'==', 595 '>=':'>=', 596 '<=':'<=', 597 '!=':'!=', 598 '>':'>', 599 '<':'<', 600 'or':' or ', 601 'and':' and '} 602
603 - def __init__(self, *args,**kw):
604 """Initialize the lex and yacc""" 605 606 self.changes_performed = 0 607 608 if len(args) > 0: 609 if isinstance(args[0],dict): 610 self.defined_variables = copy.copy(args[0]) 611 elif isinstance(args[0],str): 612 try: 613 self.defined_variables = eval(args[0]) 614 except: 615 raise ModelError, 'The expression "%s"'%str(args[0])+\ 616 " given as defined variables for the UFOExpressionParserPythonIF"+\ 617 " does not have a correct syntax." 618 if not isinstance(self.defined_variables, dict): 619 raise ModelError, 'The argument "%s"'%str(args[0])+\ 620 " given as defined variables for the UFOExpressionParserPythonIF"+\ 621 " is not a dictionary." 622 else: 623 raise ModelError, "The argument %s"%str(args[0])+\ 624 " given as defined variables for the UFOExpressionParserPythonIF"+\ 625 " must be either a dictionary or a string." 626 args = args[1:] 627 for key, value in self.defined_variables.items(): 628 if not isinstance(key,str) or \ 629 not any(isinstance(value,t) for t in [float,complex,int]): 630 # This is not a valid environment variable for the parser 631 del self.defined_variables[key] 632 633 else: 634 # If the user doesn't specify any defined variable for this parser, this means 635 # that it shouldn't do anything, not even simplify trivial conditional expressions 636 # such as '1 if True else 2' 637 self.defined_variables = None 638 639 super(UFOExpressionParserPythonIF,self).__init__(*args, **kw)
640
641 - def parse(self, *args, **kw):
642 """ Wrapper around the parse function so as to also return the number 643 of if substitutions made.""" 644 self.changes_performed = 0 645 new_expression = super(UFOExpressionParserPythonIF,self).parse(*args, **kw) 646 return new_expression, self.changes_performed
647
648 - def p_expression_number(self, p):
649 "expression : NUMBER" 650 p[0] = p[1]
651
652 - def p_expression_variable(self, p):
653 "expression : VARIABLE" 654 p[0] = p[1]
655
656 - def p_expression_power(self, p):
657 'expression : expression POWER expression' 658 p[0] = p[1] + "**" + p[3]
659
660 - def p_expression_if(self,p):
661 "expression : expression IF boolexpression ELSE expression " 662 if self.defined_variables is None: 663 p[0] = '%s if %s else %s'%(p[1],p[3],p[5]) 664 return 665 try: 666 p[0] = '%s'%p[1] if eval(p[3],self.defined_variables) else '%s'%p[5] 667 self.changes_performed += 1 668 except Exception: 669 p[0] = '%s if %s else %s'%(p[1],p[3],p[5])
670
671 - def p_expression_ifimplicit(self,p):
672 "expression : expression IF expression ELSE expression " 673 if self.defined_variables is None: 674 p[0] = '%s if %s!=0.0 else %s'%(p[1],p[3],p[5]) 675 return 676 try: 677 p[0] = '%s'%p[1] if eval(p[3]+'!= 0.0',self.defined_variables) else '%s'%p[5] 678 self.changes_performed += 1 679 except Exception: 680 p[0] = '%s if %s!=0.0 else %s'%(p[1],p[3],p[5])
681
682 - def p_expression_cond(self, p):
683 "expression : COND '(' expression ',' expression ',' expression ')'" 684 # We assume the cond syntax is used by the Model builder when he doesn't want it to 685 # get simplified, ever. 686 p[0] = 'cond('+p[3]+','+p[5]+','+p[7]+')'
687
688 - def p_expression_complex(self, p):
689 "expression : COMPLEX '(' expression ',' expression ')'" 690 p[0] = 'complex(' + p[3] + ',' + p[5] + ')'
691
692 - def p_expression_recms(self, p):
693 "expression : RECMS '(' boolexpression ',' expression ')'" 694 p[0] = 'recms('+p[3]+','+p[5]+')'
695
696 - def p_expression_func(self, p):
697 '''expression : CSC group 698 | SEC group 699 | ACSC group 700 | ASEC group 701 | RE group 702 | IM group 703 | ARG group 704 | SQRT group 705 | TAN group 706 | CONJ group 707 | REGLOG group 708 | REGLOGP group 709 | REGLOGM group''' 710 if p[1] == 'csc': p[0] = 'csc' + p[2] 711 elif p[1] == 'sec': p[0] = 'sec' + p[2] 712 elif p[1] == 'acsc': p[0] = 'acsc' + p[2] 713 elif p[1] == 'asec': p[0] = 'asec' + p[2] 714 elif p[1] in ['tan','cmath.tan']: p[0] = 'tan' + p[2] 715 elif p[1] == 're': p[0] = 're' + p[2] 716 elif p[1] == 'im': p[0] = 'im' + p[2] 717 elif p[1] == 'arg': p[0] = 'arg' + p[2] 718 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'cmath.sqrt' + p[2] 719 elif p[1] == 'complexconjugate': p[0] = 'complexconjugate' + p[2] 720 elif p[1] == 'reglog': p[0] = 'reglog' + p[2] 721 elif p[1] == 'reglogp': p[0] = 'reglogp' + p[2] 722 elif p[1] == 'reglogm': p[0] = 'reglogm' + p[2]
723
724 - def p_expression_real(self, p):
725 ''' expression : expression RE2 ''' 726 p[0] = p[1]+p[2]
727
728 - def p_expression_pi(self, p):
729 '''expression : PI''' 730 p[0] = 'cmath.pi'
731 732 733 734 # Main program, allows to interactively test the parser 735 if __name__ == '__main__': 736 737 if len(sys.argv) == 1: 738 print "Please specify a parser: fortran, mpfortran or c++" 739 exit() 740 if sys.argv[1] == "fortran": 741 calc = UFOExpressionParserFortran() 742 elif sys.argv[1] == "mpfortran": 743 calc = UFOExpressionParserMPFortran() 744 elif sys.argv[1] == "c++": 745 calc = UFOExpressionParserCPP() 746 elif sys.argv[1] == "aloha": 747 calc = UFOExpressionParserCPP() 748 elif sys.argv[1] == "pythonif": 749 if len(sys.argv) > 2: 750 calc = UFOExpressionParserPythonIF(sys.argv[2]) 751 else: 752 calc = UFOExpressionParserPythonIF() 753 else: 754 print "Please specify a parser: fortran, mpfortran, c++ or pythonif" 755 print "You gave", sys.argv[1] 756 if len(sys.argv) > 2: 757 print "with the second argument",sys.argv[2] 758 exit() 759 760 while 1: 761 try: 762 s = raw_input('calc > ') 763 except EOFError: 764 break 765 if not s: continue 766 print calc.parse(s) 767