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