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' 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 - def p_group_parentheses_boolexpr(self, p):
244 "boolexpression : '(' boolexpression ')'" 245 p[0] = '(' + p[2] +')'
246
247 - def p_expression_group(self, p):
248 "expression : group" 249 p[0] = p[1]
250
251 - def p_expression_function1(self, p):
252 "expression : FUNCTION '(' expression ')'" 253 p1 = p[1] 254 re_groups = self.re_cmath_function.match(p1) 255 if re_groups: 256 p1 = re_groups.group("name") 257 p[0] = p1 + '(' + p[3] + ')'
258
259 - def p_expression_function2(self, p):
260 "expression : FUNCTION '(' expression ',' expression ')'" 261 p1 = p[1] 262 re_groups = self.re_cmath_function.match(p1) 263 if re_groups: 264 p1 = re_groups.group("name") 265 p[0] = p1 + '(' + p[3] + ',' + p[5] + ')'
266
267 - def p_error(self, p):
268 if p: 269 raise ModelError("Syntax error at '%s' (%s)." %(p.value,p)) 270 else: 271 logger.error("Syntax error at EOF") 272 self.parsed_string = "Error"
273
274 -class UFOExpressionParserFortran(UFOExpressionParser):
275 """A parser for UFO algebraic expressions, outputting 276 Fortran-style code.""" 277 278 279 280 # The following parser expressions need to be defined for each 281 # output language/framework 282 283 logical_equiv = {'==':'.EQ.', 284 '>=':'.GE.', 285 '<=':'.LE.', 286 '!=':'.NE.', 287 '>':'.GT.', 288 '<':'.LT.', 289 'or':'.OR.', 290 'and':'.AND.'} 291
292 - def __init__(self, *args, **opts):
293 """ """ 294 out = super(UFOExpressionParserFortran,self).__init__(*args, **opts) 295 self.to_define = set()
296
297 - def clean(self):
298 """remove information about object parse for previous parsing 299 """ 300 self.to_define = set()
301 302 303 304
305 - def p_expression_number(self, p):
306 "expression : NUMBER" 307 if p[1].endswith('j'): 308 p[0] = ('DCMPLX(0d0, %e)' % float(p[1][:-1])).replace('e', 'd') 309 else: 310 p[0] = ('%e' % float(p[1])).replace('e', 'd')
311
312 - def p_expression_variable(self, p):
313 "expression : VARIABLE" 314 p[0] = p[1].lower()
315
316 - def p_expression_power(self, p):
317 'expression : expression POWER expression' 318 try: 319 p3 = float(p[3].replace('d','e')) 320 # Chebck if exponent is an integer 321 if p3 == int(p3): 322 p3 = str(int(p3)) 323 p[0] = p[1] + "**" + p3 324 else: 325 p[0] = p[1] + "**" + p[3] 326 except Exception: 327 p[0] = p[1] + "**" + p[3]
328
329 - def p_expression_if(self,p):
330 "expression : expression IF boolexpression ELSE expression " 331 p[0] = 'CONDIF(%s,DCMPLX(%s),DCMPLX(%s))' % (p[3], p[1], p[5]) 332 self.to_define.add('condif')
333
334 - def p_expression_ifimplicit(self,p):
335 "expression : expression IF expression ELSE expression " 336 p[0] = 'CONDIF(DCMPLX(%s).NE.(0d0,0d0),DCMPLX(%s),DCMPLX(%s))'\ 337 %(p[3], p[1], p[5]) 338 self.to_define.add('condif')
339
340 - def p_expression_cond(self, p):
341 "expression : COND '(' expression ',' expression ',' expression ')'" 342 p[0] = 'COND(DCMPLX('+p[3]+'),DCMPLX('+p[5]+'),DCMPLX('+p[7]+'))' 343 self.to_define.add('cond')
344
345 - def p_expression_recms(self, p):
346 "expression : RECMS '(' boolexpression ',' expression ')'" 347 p[0] = 'RECMS('+p[3]+',DCMPLX('+p[5]+'))' 348 self.to_define.add('recms')
349
350 - def p_expression_complex(self, p):
351 "expression : COMPLEX '(' expression ',' expression ')'" 352 p[0] = 'DCMPLX(' + p[3] + ',' + p[5] + ')'
353
354 - def p_expression_func(self, p):
355 '''expression : CSC group 356 | SEC group 357 | ACSC group 358 | ASEC group 359 | RE group 360 | IM group 361 | ARG group 362 | SQRT group 363 | CONJ group 364 | REGLOG group 365 | REGLOGP group 366 | REGLOGM group 367 | TAN group 368 | ATAN group''' 369 370 if p[1] == 'csc': p[0] = '1d0/sin' + p[2] 371 elif p[1] == 'sec': p[0] = '1d0/cos' + p[2] 372 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')' 373 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')' 374 elif p[1] in ['atan', 'cmath.atan'] : p[0] = 'atan(dble' + p[2]+')' 375 elif p[1] in ['tan', 'cmath.tan'] : p[0] = 'tan(dble' + p[2]+')' 376 elif p[1] == 're': p[0] = 'dble' + p[2] 377 elif p[1] == 'im': p[0] = 'dimag' + p[2] 378 elif p[1] == 'arg': p[0] = 'arg(DCMPLX'+p[2]+')' 379 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt(dcmplx' + p[2]+')' 380 elif p[1] == 'complexconjugate': p[0] = 'conjg(DCMPLX' + p[2]+')' 381 elif p[1] == 'reglog': p[0] = 'reglog(DCMPLX' + p[2] +')' 382 elif p[1] == 'reglogp': p[0] = 'reglogp(DCMPLX' + p[2] + ')' 383 elif p[1] == 'reglogm': p[0] = 'reglogm(DCMPLX' + p[2] + ')' 384 385 if p[1] in ['reglog', 'reglogp', 'reglogm']: 386 self.to_define.add(p[1])
387
388 - def p_expression_real(self, p):
389 ''' expression : expression RE2 ''' 390 391 if p[2] == '.real': 392 if p[1].startswith('('): 393 p[0] = 'dble' +p[1] 394 else: 395 p[0] = 'dble(%s)' % p[1] 396 elif p[2] == '.imag': 397 if p[1].startswith('('): 398 p[0] = 'dimag' +p[1] 399 else: 400 p[0] = 'dimag(%s)' % p[1]
401
402 - def p_expression_pi(self, p):
403 '''expression : PI''' 404 p[0] = 'pi' 405 self.to_define.add('pi')
406
407 -class UFOExpressionParserMPFortran(UFOExpressionParserFortran):
408 """A parser for UFO algebraic expressions, outputting 409 Fortran-style code for quadruple precision computation.""" 410 411 mp_prefix = check_param_card.ParamCard.mp_prefix 412 413 # The following parser expressions need to be defined for each 414 # output language/framework 415
416 - def p_expression_number(self, p):
417 "expression : NUMBER" 418 419 if p[1].endswith('j'): 420 p[0] = 'CMPLX(0.000000e+00_16, %e_16 ,KIND=16)' % float(p[1][:-1]) 421 else: 422 p[0] = '%e_16' % float(p[1])
423
424 - def p_expression_variable(self, p):
425 "expression : VARIABLE" 426 # All the multiple_precision variables are defined with the prefix _MP_" 427 p[0] = (self.mp_prefix+p[1]).lower()
428
429 - def p_expression_power(self, p):
430 'expression : expression POWER expression' 431 try: 432 p3 = float(p[3].replace('_16','')) 433 # Check if exponent is an integer 434 if p3 == int(p3): 435 p3 = str(int(p3)) 436 p[0] = p[1] + "**" + p3 437 else: 438 p[0] = p[1] + "**" + p[3] 439 except Exception: 440 p[0] = p[1] + "**" + p[3]
441
442 - def p_expression_if(self,p):
443 "expression : expression IF boolexpression ELSE expression " 444 p[0] = 'MP_CONDIF(%s,CMPLX(%s,KIND=16),CMPLX(%s,KIND=16))' % (p[3], p[1], p[5]) 445 self.to_define.add('mp_condif')
446
447 - def p_expression_ifimplicit(self,p):
448 "expression : expression IF expression ELSE expression " 449 p[0] = 'MP_CONDIF(CMPLX(%s,KIND=16).NE.(0.0e0_16,0.0e0_16),CMPLX(%s,KIND=16),CMPLX(%s,KIND=16))'\ 450 %(p[3], p[1], p[5]) 451 self.to_define.add('mp_condif')
452
453 - def p_expression_complex(self, p):
454 "expression : COMPLEX '(' expression ',' expression ')'" 455 p[0] = 'CMPLX(' + p[3] + ',' + p[5] + ',KIND=16)'
456
457 - def p_expression_cond(self, p):
458 "expression : COND '(' expression ',' expression ',' expression ')'" 459 p[0] = 'MP_COND(CMPLX('+p[3]+',KIND=16),CMPLX('+p[5]+\ 460 ',KIND=16),CMPLX('+p[7]+',KIND=16))' 461 self.to_define.add('mp_cond')
462
463 - def p_expression_recms(self, p):
464 "expression : RECMS '(' boolexpression ',' expression ')'" 465 p[0] = 'MP_RECMS('+p[3]+',CMPLX('+p[5]+',KIND=16))' 466 self.to_define.add('mp_recms')
467
468 - def p_expression_func(self, p):
469 '''expression : CSC group 470 | SEC group 471 | ACSC group 472 | ASEC group 473 | RE group 474 | IM group 475 | ARG group 476 | SQRT group 477 | CONJ group 478 | REGLOG group 479 | REGLOGP group 480 | REGLOGM group 481 | TAN group 482 | ATAN group''' 483 484 if p[1] == 'csc': p[0] = '1e0_16/cos' + p[2] 485 elif p[1] == 'sec': p[0] = '1e0_16/sin' + p[2] 486 elif p[1] == 'acsc': p[0] = 'asin(1e0_16/' + p[2] + ')' 487 elif p[1] == 'asec': p[0] = 'acos(1e0_16/' + p[2] + ')' 488 elif p[1] in ['atan', 'cmath.atan'] : p[0] = 'atan(real' + p[2]+')' 489 elif p[1] in ['tan', 'cmath.tan']: p[0] = 'tan(real' + p[2]+')' 490 elif p[1] == 're': p[0] = 'real' + p[2] 491 elif p[1] == 'im': p[0] = 'imag' + p[2] 492 elif p[1] == 'arg': p[0] = 'mp_arg(CMPLX(' + p[2] + ',KIND=16))' 493 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt(CMPLX(' + p[2] + ',KIND=16))' 494 elif p[1] == 'complexconjugate': p[0] = 'conjg(CMPLX(' + p[2] + ',KIND=16))' 495 elif p[1] == 'reglog': p[0] = 'mp_reglog(CMPLX(' + p[2] +',KIND=16))' 496 elif p[1] == 'reglogp': p[0] = 'mp_reglogp(CMPLX(' + p[2] + ',KIND=16))' 497 elif p[1] == 'reglogm': p[0] = 'mp_reglogm(CMPLX(' + p[2] + ',KIND=16))' 498 499 if p[1] in ['reglog', 'reglogp', 'reglogm']: 500 self.to_define.add(p[1])
501
502 - def p_expression_real(self, p):
503 ''' expression : expression RE2 ''' 504 505 if p[2] == '.real': 506 if p[1].startswith('('): 507 p[0] = 'real' +p[1] 508 else: 509 p[0] = 'real(%s)' % p[1] 510 elif p[2] == '.imag': 511 if p[1].startswith('('): 512 p[0] = 'imag' +p[1] 513 else: 514 p[0] = 'imag(%s)' % p[1]
515 516
517 - def p_expression_pi(self, p):
518 '''expression : PI''' 519 p[0] = self.mp_prefix+'pi' 520 self.to_define.add(self.mp_prefix+'pi')
521
522 -class UFOExpressionParserCPP(UFOExpressionParser):
523 """A parser for UFO algebraic expressions, outputting 524 C++-style code.""" 525 526 logical_equiv = {'==':'==', 527 '>=':'>=', 528 '<=':'<=', 529 '!=':'!=', 530 '>':'>', 531 '<':'<', 532 'or':'||', 533 'and':'&&'} 534 535 # The following parser expressions need to be defined for each 536 # output language/framework 537
538 - def p_expression_number(self, p):
539 'expression : NUMBER' 540 541 if p[1].endswith('j'): 542 p[0] = 'std::complex<double>(0., %e)' % float(p[1][:-1]) 543 else: 544 p[0] = ('%e' % float(p[1])).replace('e', 'd') 545 546 547 p[0] = p[1] 548 # Check number is an integer, if so add "." 549 if float(p[1]) == int(float(p[1])) and float(p[1]) < 1000: 550 p[0] = str(int(float(p[1]))) + '.'
551
552 - def p_expression_variable(self, p):
553 'expression : VARIABLE' 554 p[0] = p[1]
555
556 - def p_expression_if(self,p):
557 "expression : expression IF boolexpression ELSE expression " 558 p[0] = '(%s ? %s : %s)' % (p[3], p[1], p[5])
559
560 - def p_expression_ifimplicit(self,p):
561 "expression : expression IF expression ELSE expression " 562 p[0] = '(%s ? %s : %s)' % (p[3], p[1], p[5])
563
564 - def p_expression_cond(self, p):
565 "expression : COND '(' expression ',' expression ',' expression ')'" 566 p[0] = 'COND('+p[3]+','+p[5]+','+p[7]+')'
567
568 - def p_expression_recms(self, p):
569 "expression : RECMS '(' boolexpression ',' expression ')'" 570 p[0] = 'RECMS('+p[3]+','+p[5]+')'
571
572 - def p_expression_power(self, p):
573 'expression : expression POWER expression' 574 p1=p[1] 575 p3=p[3] 576 if p[1][0] == '(' and p[1][-1] == ')': 577 p1 = p[1][1:-1] 578 if p[3][0] == '(' and p[3][-1] == ')': 579 p3 = p[3][1:-1] 580 if float(p3) == 2: 581 p[0] = '((' + p1 + ')*(' + p1 + '))' 582 elif float(p3) == 3: 583 p[0] = '((' + p1 + ')*(' + p1 + ')*(' + p1 + '))' 584 elif float(p3) == 4: 585 p[0] = '((' + p1 + ')*(' + p1 + ')*(' + p1 + ')*(' + p1 + '))' 586 elif float(p3) == 0.5 or p3 == '0.5' or p3 == '1./2' or p3 == '1/2.' or p3 == '1./2.': 587 p[0] = 'sqrt(' + p1 + ')' 588 elif float(p3) == 1./3 or p3 == '1./3' or p3 == '1/3.' or p3 == '1./3.': 589 p[0] = 'cbrt(' + p1 + ')' 590 else: 591 p[0] = 'pow(' + p1 + ',' + p3 + ')'
592
593 - def p_expression_complex(self, p):
594 "expression : COMPLEX '(' expression ',' expression ')'" 595 p[0] = 'std::complex<double>(' + p[3] + ',' + p[5] + ')'
596
597 - def p_expression_func(self, p):
598 '''expression : CSC group 599 | SEC group 600 | ACSC group 601 | ASEC group 602 | TAN group 603 | ATAN group 604 | RE group 605 | IM group 606 | ARG group 607 | SQRT group 608 | CONJ group 609 | REGLOG group 610 | REGLOGP group 611 | REGLOGM group''' 612 if p[1] == 'csc': p[0] = '1./cos' + p[2] 613 elif p[1] == 'sec': p[0] = '1./sin' + p[2] 614 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')' 615 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')' 616 elif p[1] in ['atan', 'cmath.atan']: p[0] = 'atan' +p[2] 617 elif p[1] in ['tan', 'cmath.tan']: p[0] = 'tan' +p[2] 618 elif p[1] == 're': p[0] = 'real' + p[2] 619 elif p[1] == 'im': p[0] = 'imag' + p[2] 620 elif p[1] == 'arg':p[0] = 'arg' + p[2] 621 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt' + p[2] 622 elif p[1] == 'complexconjugate': p[0] = 'conj' + p[2] 623 elif p[1] == 'reglog': p[0] = 'reglog' + p[2] 624 elif p[1] == 'reglogp': p[0] = 'reglogp' + p[2] 625 elif p[1] == 'reglogm': p[0] = 'reglogm' + p[2]
626
627 - def p_expression_real(self, p):
628 ''' expression : expression RE2 ''' 629 630 if p[2] == '.real': 631 if p[1].startswith('('): 632 p[0] = 'real' +p[1] 633 else: 634 p[0] = 'real(%s)' % p[1] 635 elif p[2] == '.imag': 636 if p[1].startswith('('): 637 p[0] = 'imag' +p[1] 638 else: 639 p[0] = 'imag(%s)' % p[1]
640 641
642 - def p_expression_pi(self, p):
643 '''expression : PI''' 644 p[0] = 'M_PI'
645
646 -class UFOExpressionParserPythonIF(UFOExpressionParser):
647 """An ad hoc parser for UFO algebraic expressions with if statement, outputting 648 Python-style code, with the conditional 'if' expressions simplified using 649 pre-defined set of variables specified when instanciating this parser.""" 650 651 logical_equiv = {'==':'==', 652 '>=':'>=', 653 '<=':'<=', 654 '!=':'!=', 655 '>':'>', 656 '<':'<', 657 'or':' or ', 658 'and':' and '} 659
660 - def __init__(self, *args,**kw):
661 """Initialize the lex and yacc""" 662 663 self.changes_performed = 0 664 665 if len(args) > 0: 666 if isinstance(args[0],dict): 667 self.defined_variables = copy.copy(args[0]) 668 elif isinstance(args[0],str): 669 try: 670 self.defined_variables = eval(args[0]) 671 except: 672 raise ModelError, 'The expression "%s"'%str(args[0])+\ 673 " given as defined variables for the UFOExpressionParserPythonIF"+\ 674 " does not have a correct syntax." 675 if not isinstance(self.defined_variables, dict): 676 raise ModelError, 'The argument "%s"'%str(args[0])+\ 677 " given as defined variables for the UFOExpressionParserPythonIF"+\ 678 " is not a dictionary." 679 else: 680 raise ModelError, "The argument %s"%str(args[0])+\ 681 " given as defined variables for the UFOExpressionParserPythonIF"+\ 682 " must be either a dictionary or a string." 683 args = args[1:] 684 for key, value in self.defined_variables.items(): 685 if not isinstance(key,str) or \ 686 not any(isinstance(value,t) for t in [float,complex,int]): 687 # This is not a valid environment variable for the parser 688 del self.defined_variables[key] 689 690 else: 691 # If the user doesn't specify any defined variable for this parser, this means 692 # that it shouldn't do anything, not even simplify trivial conditional expressions 693 # such as '1 if True else 2' 694 self.defined_variables = None 695 696 super(UFOExpressionParserPythonIF,self).__init__(*args, **kw)
697
698 - def parse(self, *args, **kw):
699 """ Wrapper around the parse function so as to also return the number 700 of if substitutions made.""" 701 self.changes_performed = 0 702 new_expression = super(UFOExpressionParserPythonIF,self).parse(*args, **kw) 703 return new_expression, self.changes_performed
704
705 - def p_expression_number(self, p):
706 "expression : NUMBER" 707 p[0] = p[1]
708
709 - def p_expression_variable(self, p):
710 "expression : VARIABLE" 711 p[0] = p[1]
712
713 - def p_expression_power(self, p):
714 'expression : expression POWER expression' 715 p[0] = p[1] + "**" + p[3]
716
717 - def p_expression_if(self,p):
718 "expression : expression IF boolexpression ELSE expression " 719 if self.defined_variables is None: 720 p[0] = '%s if %s else %s'%(p[1],p[3],p[5]) 721 return 722 try: 723 p[0] = '%s'%p[1] if eval(p[3],self.defined_variables) else '%s'%p[5] 724 self.changes_performed += 1 725 except Exception: 726 p[0] = '%s if %s else %s'%(p[1],p[3],p[5])
727
728 - def p_expression_ifimplicit(self,p):
729 "expression : expression IF expression ELSE expression " 730 if self.defined_variables is None: 731 p[0] = '%s if %s!=0.0 else %s'%(p[1],p[3],p[5]) 732 return 733 try: 734 p[0] = '%s'%p[1] if eval(p[3]+'!= 0.0',self.defined_variables) else '%s'%p[5] 735 self.changes_performed += 1 736 except Exception: 737 p[0] = '%s if %s!=0.0 else %s'%(p[1],p[3],p[5])
738
739 - def p_expression_cond(self, p):
740 "expression : COND '(' expression ',' expression ',' expression ')'" 741 # We assume the cond syntax is used by the Model builder when he doesn't want it to 742 # get simplified, ever. 743 p[0] = 'cond('+p[3]+','+p[5]+','+p[7]+')'
744
745 - def p_expression_complex(self, p):
746 "expression : COMPLEX '(' expression ',' expression ')'" 747 p[0] = 'complex(' + p[3] + ',' + p[5] + ')'
748
749 - def p_expression_recms(self, p):
750 "expression : RECMS '(' boolexpression ',' expression ')'" 751 p[0] = 'recms('+p[3]+','+p[5]+')'
752
753 - def p_expression_func(self, p):
754 '''expression : CSC group 755 | SEC group 756 | ACSC group 757 | ASEC group 758 | RE group 759 | IM group 760 | ARG group 761 | SQRT group 762 | TAN group 763 | ATAN group 764 | CONJ group 765 | REGLOG group 766 | REGLOGP group 767 | REGLOGM group''' 768 if p[1] == 'csc': p[0] = 'csc' + p[2] 769 elif p[1] == 'sec': p[0] = 'sec' + p[2] 770 elif p[1] == 'acsc': p[0] = 'acsc' + p[2] 771 elif p[1] == 'asec': p[0] = 'asec' + p[2] 772 elif p[1] in ['tan','cmath.tan']: p[0] = 'tan' + p[2] 773 elif p[1] in ['atan','cmath.atan']: p[0] = 'atan' + p[2] 774 elif p[1] == 're': p[0] = 're' + p[2] 775 elif p[1] == 'im': p[0] = 'im' + p[2] 776 elif p[1] == 'arg': p[0] = 'arg' + p[2] 777 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'cmath.sqrt' + p[2] 778 elif p[1] == 'complexconjugate': p[0] = 'complexconjugate' + p[2] 779 elif p[1] == 'reglog': p[0] = 'reglog' + p[2] 780 elif p[1] == 'reglogp': p[0] = 'reglogp' + p[2] 781 elif p[1] == 'reglogm': p[0] = 'reglogm' + p[2]
782
783 - def p_expression_real(self, p):
784 ''' expression : expression RE2 ''' 785 p[0] = p[1]+p[2]
786
787 - def p_expression_pi(self, p):
788 '''expression : PI''' 789 p[0] = 'cmath.pi'
790 791 792 793 # Main program, allows to interactively test the parser 794 if __name__ == '__main__': 795 796 if len(sys.argv) == 1: 797 print "Please specify a parser: fortran, mpfortran or c++" 798 exit() 799 if sys.argv[1] == "fortran": 800 calc = UFOExpressionParserFortran() 801 elif sys.argv[1] == "mpfortran": 802 calc = UFOExpressionParserMPFortran() 803 elif sys.argv[1] == "c++": 804 calc = UFOExpressionParserCPP() 805 elif sys.argv[1] == "aloha": 806 calc = UFOExpressionParserCPP() 807 elif sys.argv[1] == "pythonif": 808 if len(sys.argv) > 2: 809 calc = UFOExpressionParserPythonIF(sys.argv[2]) 810 else: 811 calc = UFOExpressionParserPythonIF() 812 else: 813 print "Please specify a parser: fortran, mpfortran, c++ or pythonif" 814 print "You gave", sys.argv[1] 815 if len(sys.argv) > 2: 816 print "with the second argument",sys.argv[2] 817 exit() 818 819 while 1: 820 try: 821 s = raw_input('calc > ') 822 except EOFError: 823 break 824 if not s: continue 825 print calc.parse(s) 826