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